I Published the Rule and Built the Hole Eight Days Later
Correction, 2026-10-08. The data app this post offers as the one that went the other way did not get this right. The day this post went up, a forged-header probe against it in production showed its limiter keying every failed sign-in on the hosting edge's own address, not the visitor's. On that host the last forwarded entry is written by the edge itself. Every visitor shared a bucket with everyone else, so a few wrong passwords from anyone could lock everyone out of sign-in. It was fixed the same day, and a second probe logged the visitor's real address. The August audit reasoned its way to the last hop from the source. Only a check run against the deployment showed that the last hop was the edge. The text below is struck through where it no longer holds.
Two of my essays went onto this site on September 12. One says a tool bound to localhost is still a network service, because the browser is the boundary. The other says a rate limiter behind a proxy has to count the visitor's address, not the proxy's. The site dates them August 30 and August 1, because I dated the backfill to when the work happened, but they went live on the twelfth.
Eight days later, on September 20, I built a local secrets vault for my access tokens. Its first commit says the opposite of the first essay, in three places.
The Sentence That Read Like Reasoning
The vault's code header says it binds to loopback and nothing else, that there's no login and never will be, and that loopback is the access control because "an auth system would only add a surface that could be wrong." The README says it again, and so does the page footer. The header goes on to call the bind address the most security-relevant line in the program.
That's a confident paragraph with a reason attached, which is the dangerous kind. A bare "no login" reads as a gap. This reads as a decision somebody weighed, and it had weighed the wrong boundary. The browser is the boundary. I'd said so in public eight days earlier, and I'd fixed the same hole in claude-code-log on August 28, twenty-three days before.
Every commit I cite here has an agent co-author trailer, both the ones that built the hole and the ones that closed it. So the useful question is what the build could read, not who forgot. Search my global instructions, my skills and commands, and each repo's own instruction file and memory, and nothing turns up on the loopback lesson. The vault repo has no instruction file at all. The lesson lived in a blog post and in one public repo's code, and nothing a new build opens points to either.
Eleven Days
The fix landed on October 1, eleven days after the first commit, and its message says it plainly: "Loopback does not stop a web page in the owner's browser." For eleven days, any page open in my browser could have reached the vault. Now the vault refuses requests addressed to anything but loopback, and requests the browser marks as coming from another site.
Nothing in the commits says anyone used the hole. It was exposed, and that's the finding.
A second commit the same day found a smaller version of the same habit: secret reveals left no trace, and the README said they did. The first essay had a line for that: your documentation is not a sensor.
The header sentence is still in the file. The fix is a paragraph underneath it saying loopback doesn't stop a web page. The rationale was never deleted, only footnoted.
The Tool That Predates the Rule
A markdown viewer of mine got the same fix on the same day, 156 days after its first commit on April 28. Its README said "Single user, localhost only, no auth." The fix commit says a page that rebinds its name to loopback could read every markdown file under my projects folder.
That one wasn't re-broken after I published anything. It was built before the lesson existed, and the lesson never went back for it.
The Limiter, a Third Time
The rate-limiter essay says "There will be a third time." It turned up in a navigation app's web sign-in, where the limiter counted one of my hosting platform's rotating edge addresses instead of the visitor's. The fix is dated October 2. A comment committed to that same codebase on July 20 already said that behind the platform's proxy every request shares one address. Knowing it in a comment didn't reach the sign-in limiter.
Three days later, on October 5, a second fix landed for the same class, one layer in. The web app has its own proxy in front of the API, so every web visitor still arrived from one address, and one person could use up the shared limit and lock everyone out of web sign-in. That's fixed. A production probe on October 6 showed a forged forwarded-for value being ignored.
One data point goes the other way looked like it went the other way (corrected 2026-10-08). A small public data app got this right set out to fix this on August 16, in an audit commit that counts the last forwarded hop and says why: the first entry hands an attacker a fresh bucket per request. (Corrected 2026-10-08: on that host the last forwarded entry is the host's own edge, so the fix counted the proxy. See the correction above.) The same commit admits its docs had claimed a login throttle for weeks that did not exist. That fix came from an audit of fifteen findings checked against the source, not from an essay.
What Carried the Fix
Not the essays. On October 1 the same refusal of foreign host names went into four of my local tools between 12:28 and 18:14, two of them the vault and the viewer. Neither the vault commit nor the viewer commit mentions either essay. The commits don't say what prompted each one, and I won't guess. What I can show is a day of hardening commits doing what a published rule hadn't done in the weeks before.
What Exists Now
Not much. Nothing I have checks for the loopback class. No skill, command, hook or instruction file mentions it, and the security sweep skill checks for committed secrets and dependency advisories and nothing else.
For the proxy class there's one line in my auth template. It only runs when I invoke it, and it doesn't test anything. The template needs the test the rate-limiter essay asked for: send forged headers at the real deployment.
What does exist is a regression test per fix, in the vault, the viewer and the navigation app. Those keep three repos from breaking again and do nothing for the fourth.
The check that would fit is boring, and it doesn't exist yet. Start the tool, send one request addressed to a name that isn't loopback, and fail the build if it answers. Send two requests with different forged forwarded-for values and fail if they share a bucket. Those are the forge-the-header-and-count step from the rate-limiter essay and the look-at-the-artifact rule from the first one, run on every new repo by something other than my memory.
The rules essay on this site says a rule has to be specific enough to bind an agent, and it has to sit in a file the agent reads. I wrote two lessons down. One reached a template that runs on request, and the other reached no file at all. A lesson that lives only in a post gets learned again, one repo at a time.
-- Justin Higgins. Software Engineer, Midwest. Wrote the rule down, published it, and shipped the hole anyway.
Companion pieces: Verify the Artifact, Not the Process - the loopback rule this build failed to carry. Your Rate Limiter Is Counting the Wrong IP - the other lesson, which predicted a third time.
Reactions, disagreements, war stories: jchigg2000.dev@gmail.com