I hadn't actually closed the doorproject
A casual security probe was supposed to bounce off my vault door. Instead it strolled in, and the page that loaded was the login screen for the one service in my lab that can physically unlock my home’s front door. This would have been an alarming way to start a Saturday, except it wasn’t Saturday and it wasn’t news: I was fact-checking a blog post I had already written, one you’ll now never read, about having fixed this exact security hole, weeks earlier, in the past tense. Oops.
Some background, because this oversight needs context. A while back, I implemented a proper security practice in my homelab: a regular inventory of everything I run, then an assessment workflow built on one borrowed-from-the-pros idea, test who can actually reach each thing, not only who’s supposed to. My smart home runs Home Assistant, which can actuate real deadbolts, so day-to-day I reach it over Tailscale, the private mesh I’ve described before: the convenience of the open web with none of the exposure, no memorized addresses, no ports open to anyone, nothing reachable except by devices I own. The design rule was strict, and I was proud of it. Reachable from outside only through an identity gate (Cloudflare Access) that admits members of my household and no one else.
The first assessment, back then, said the gate was missing. I dug in, found a stale allow-rule added during a past experiment that had widened it to admit an AI vendor’s whole network, removed the rule, and wrote the triumphant post you are now not reading, the one where a careful audit finds a real problem and the operator quietly fixes it. I even had a tidy lesson about measuring reachability from the right vantage point. I was, it turns out, measuring the wrong thing and drawing the wrong conclusion, which is the precise failure that lesson was about. The post was right that asserted policy and observed reachability can diverge. It just didn’t notice they had diverged in its own author’s house.
Here is the part that saves the story from being pure faceplant. Every post on this blog runs through a pre-publish check before it ships, built because AI-drafted prose can drift confidently away from the truth if left to its own devices. So before publishing a security post, the check does the obvious thing: it probes the service from outside, the way a stranger would. That probe unfortunately reached the login page. No identity gate, no challenge, on the internet, in front of my home locks. The fix I had written up in the past tense had not, in the present tense, occurred.
The real cause was one layer down from where I’d been looking. A catch-all DNS rule in Cloudflare keeps every service in my domain private by default, resolvable only from inside my mesh. But a single tunnel route, added for a long-dead integration, had published this one service straight to the public internet with a more specific record that quietly overruled the catch-all and skipped the identity gate entirely. My July fix had addressed a real but secondary detail on a door the traffic was never using. The actual door had been standing open the whole time, and every probe I’d trusted since had been reading the wrong doorway.
The fix this time was one deletion: remove the stale route, and the service falls back to private-by-default, reachable only over the mesh, exactly as designed. And this time I did not take my own word for it. I re-ran the outside probe: it can no longer resolve the address, and any request that reaches the edge now meets the gate and stops. Then to be sure, I generated a read-only API token and had my tools review the actual configuration end to end, checking every other service in the estate for the same shape at the same time. Thankfully, there were no other offenders. This one had been enough.
The lesson I’ll actually keep is not the one I set out to write. I had described a fix without ever watching it work, and the writing had gotten ahead of the truth. What turned my description into a fact was a boring, automated skeptic that probes my own work and doesn’t care how sure I sounded in the draft. It was written to catch the blog lying to my readers. Its first real catch was the author lying to himself.