2026-06-24: Closing the LAN — the loopback surface sweep

The passkey and the machine certs locked the front door. The crown jewels sat behind mTLS. Windu, the security seat, was not satisfied — a locked door means nothing when the windows are open. So we counted the windows: every service on the haus that was listening for a connection. The question for each was small and merciless. Who actually needs to reach you? Several answered 0.0.0.0 — every interface, any device on the home LAN. This is the sweep that shut them.
The lock came from the passkey and mTLS hardening two days earlier. This is the follow-through.
The doctrine: bind to need, never to 0.0.0.0
Section titled “The doctrine: bind to need, never to 0.0.0.0”A service bound to 0.0.0.0 is making an offer: anyone on any network I touch may connect. Almost nothing needs to make that offer. One rule, three cases:
- On-box only — a backend behind a terminator, a bus that only local scripts post to — binds loopback (
127.0.0.1). The LAN cannot see it. Neither can the tailnet. - A deliberate off-box need — a read-only API the travelling laptop renders from, a coordination registry the VM uses — binds loopback plus exactly the one interface it needs: the tailnet IP, or the vmnet bridge. Nothing more. The LAN is excluded.
- Mutation surfaces stay loopback, always. Reading is one risk class. Writing is another.
The second case is the subtle one. There is no bind address that means “loopback and tailnet but not the LAN.” So those services now bind a short explicit list and skip 0.0.0.0 entirely.
What moved
Section titled “What moved”Seven listeners came off the wire. The change reads more cleanly as a ledger than as a paragraph — each of these ports lives in the full port summary.
| Service | Port | Before | After |
|---|---|---|---|
| proxyd (model gateway) | :4040 | 0.0.0.0 | loopback |
| Force Flow (alerts + screen-time) | :4077 | 0.0.0.0 | loopback (tailnet via the :4078 terminator) |
| Firewalla bridge | :1984 | 0.0.0.0 | loopback |
| Sonos bridge | :1969 | 0.0.0.0 | loopback |
| sanctumd (watchdog API) | :2187 | 0.0.0.0 | loopback + tailnet |
| Holocron sidecar | :3344 | 0.0.0.0 | loopback + tailnet |
| presence (lock registry) | :1949 | 0.0.0.0 | loopback + bridge + tailnet |
sanctumd, Holocron, presence: loopback plus one
Section titled “sanctumd, Holocron, presence: loopback plus one”Three services could not simply hide. Each carries an endpoint a council ruling deliberately exposes off-box. sanctumd and Holocron render the dashboard honestly when the laptop is on the road, over the tailnet. presence lets the VM acquire and release cross-session locks, over the vmnet bridge. Their mutation surfaces already live elsewhere, on loopback.
So each binds loopback plus the resolved tailnet IP — and, for presence, the bridge too. The bind is best-effort. If Tailscale is down, the service falls back to loopback rather than failing outright. sanctumd goes one step further: its default is baked into the binary. No relaunch can undo it — not a heal, not a boot script, not anything. The LAN is off the table for good.
Left exposed on purpose
Section titled “Left exposed on purpose”A few listeners stay reachable past loopback, because that is the correct answer for them:
- The PQ-TLS terminators on
:1111,:2222,:2223, and:4078bind the tailnet by design. They are the encrypted front for the loopback backends — the same pattern the passkey dashboard uses. :7337is already tailnet-bound.:1138, the voice agent, is reached by the LiveKit cloud and by SIP, gated by Tailscale and the framework’s own TLS.
So a regression is caught, not discovered
Section titled “So a regression is caught, not discovered”Here is the honest part. The macOS application firewall does not actually gate these services — it marks them “permitted.” The binding is the real control. Not a firewall rule.
The :6669 ablation listener makes the stakes plain. It serves an uncensored model with no auth. The only thing between it and the LAN is a loopback bind. So its posture check was rewritten to assert exactly that: loopback-only, or page.
The security-posture-sentinel now sweeps the whole set every 15 minutes. It checks that the gate is enforcing, that the machine ports refuse plaintext, and that nothing sensitive has drifted back onto 0.0.0.0. When it fails, it opens the break-glass runbook. Point-in-time hardening is a snapshot. Continuous attestation is the lock — the windows get counted every fifteen minutes now, whether or not anyone is watching.