The Well Ran Dry
I published an essay saying my guard tournaments never came up empty: every round found new bypasses, because a pattern list doesn't converge. Five days later the well ran dry. On the fix that finally converged, the floor it converged onto, and the written rule for when a security hunt is allowed to stop.
In The Guard That Doesn’t Trust Itself I wrote that my adversarial tournaments against my own agent-safety guards produced new findings every single round: there was no round where the well ran dry. I meant it as a structural claim. A guard that scans command text against a finite list of dangerous patterns is not a convergent model; it generates an endless sequence of holes, not a shrinking one. That claim was true for exactly as long as I kept fixing at the wrong layer.
Five days after that essay went live, the well ran dry. This is the account of how, and of the more useful thing I found at the bottom.
One trick, seven guards
Round one opened with a two-character payload. Take a dangerous command, any dangerous command, and split its verb with a pair of empty quotes: r''m -rf ~/.
The guard sees r''m, and its pattern for the delete verb never matches, because r''m is not rm. The shell disagrees. Quote removal is one of the last things a shell does before running a command, so by execution time those empty quotes are gone and the real delete runs, flags intact. The guard read the costume. The shell ran the actor.
Every guard I have that scans command text fell to it. Seven out of seven: the destructive-command blocker, the egress guard, the git-safety wall, the remote-execution check, the confirmation gate, all of them, each defeated by the same two characters spelled into whichever verb it watched for. gi''t push. cu''rl. ev''al. These guards had been hardened repeatedly over months, and the hardening had always modeled path tricks: doubled slashes, brace expansion, variables hiding a target. Nobody had ever asked what the shell does to the verb.
The reflex at this point is seven patches, one per guard. The actual fix was one: a shared normalization step that every guard runs before matching. Remove empty quote pairs. Fold split string fragments back together. Decode the escape spellings that interpreters expand. In other words, make the guard read the command the way the shell will run it, then match. The guard and the shell had been disagreeing about what the command was, and the shell wins that argument every time, so the only stable design is to stop having the argument.
That one change is what made the next round different in kind, not just smaller.
The probe lied too
Round two found real holes, and closed them the same way. A whitespace variable can glue a command together without a single space the guard would recognize: rm${IFS}-rf${IFS}~/. An ANSI-C quoted string can spell a verb in octal: $'\162m' becomes rm on expansion. Both are transforms the shell performs, so both belong in the shared normalizer, and both went into it. No new patterns. Same layer, same fix.
Round two also handed me two embarrassments, which in this series counts as a feature.
First, my own report claimed two bypasses that did not exist. The probe I used checked each payload against one guard, the guard I expected to own that threat, and a rule in a different guard already denied the whole encode-and-pipe family. A probe that queries a subset of the guards reports OPEN when another guard catches it. So the hunt got the same treatment as the guards: fix the probe, re-run everything against all seven, and score on payloads whose correct verdict is known in advance. The instrument that audits the guards is itself a guard, and it lies in the same ways.
Second, I learned that “the guard misses it” and “it still executes” are two separate columns, and only both-true is a hole. One evasion used an invisible Unicode character inside a verb, and it defeated the guard beautifully. It also defeated the shell: a verb with an invisible character in it is not a command, so nothing ran, and the terrifying bypass was a bug with no exploit attached. I had already written it up as a live vulnerability when I ran the second column. Now every candidate bypass gets scored in both, because a red finding that cannot actually fire is a false alarm wearing red.
One more thing round two settled: some passes are decisions, not gaps. A handful of general-purpose tools can be chained into decoding tricks, and blocking them at the pipe would break entirely ordinary work. Those stay open, on purpose, with the reasoning written down. A gap nobody noticed and a trade somebody chose look identical in a scan result. They are not the same object.
The floor
Round three is where the well went dry, and it went dry in an interesting way.
Every bypass in rounds one and two shared a property I only saw afterward: the dangerous verb still existed as literal text somewhere in the string. Dressed up, split, encoded, glued, but present, which is exactly why normalization worked. There was always something to reveal.
Round three’s payloads have no verb in them at all:
$(echo r)$(echo m) -rf ~/assembles the delete verb from the output of two subcommands.X=xrmx; ${X:1:2} -rf ~/slices it out of the middle of a variable.
There is no rm in either string. The verb does not exist until the shell manufactures it at runtime, and a scanner cannot resolve $(echo r) without executing echo. A guard that executes the command it is inspecting has stopped being a guard. This is not a missing pattern. A shell is a full programming language, and a program can assemble a verb an unbounded number of ways; chasing individual spellings of runtime assembly is not slow progress, it is no progress wearing the costume of work.
The round did surface one last deterministic straggler, a line continuation splitting a verb across a backslash and a newline, which is a transform, so it went into the normalizer with the others. That was the final cheap win. Everything left standing requires execution to detect.
The stop rule
So I wrote a rule and put it where my future sessions will trip over it:
When detecting the next bypass class would require executing the command, the static layer is finished. Fix the deterministic remainder. Document the limit. Stop.
The rule exists in writing because the pull to keep digging is real, and it does not announce itself as waste. Each next step looks cheap. Security hunting has no natural finish line, findings are the reward signal, and a hunt that gets rewarded for finding will keep finding, the way round two “found” two bypasses another guard already covered. A stopping criterion has to be computable, not a mood, and mine is one sentence: if the check can’t see it without running it, the check is done.
Past that line, effort doesn’t buy safety. It buys theatre with regex in it, and worse, it buys the feeling of a hardened layer, which is the most dangerous artifact this series knows about. The budget that would have gone to round four goes where the first essay already pointed: keeping hostile content away from the tool layer in the first place, so an injected instruction never gets to spell anything, cleverly or otherwise. That backstop is architectural. No amount of pattern work substitutes for it.
What “closed” means now
The claim “all rounds closed” earns its wording the same way everything else here does, with receipts. A fresh probe, rebuilt from its written description rather than trusted from a cached copy, ran 24 payloads through all seven command guards: 168 verdicts. Every payload with a known correct answer scored correctly. Seventeen of seventeen dangerous spellings denied, including every bypass from all three rounds. Two of two legitimate look-alike controls waved through, because a guard that starts flagging innocent commands is depreciating a different way. And a few payloads still pass every guard, correctly: the runtime-assembly forms, and the general-purpose pipes we chose to leave alone. Those are not backlog. They are the floor, documented, with the stop rule standing on it.
Notice what “closed” is doing in that paragraph. It means closed for the classes I probed, against all the guards I asked, with the payload list attached. Anything more confident than that is a self-report, and this series has a standing policy on those.
The first essay needs an amendment, then, not a retraction. Per-pattern fixing really doesn’t converge; I watched it fail to converge for two tournaments, and the essay was right to say so. What converges is fixing at the layer where whole classes live: the normalizer that closed seven guards at once, the probe that asks everyone instead of one, the decision log that turns mystery passes into chosen trades. Convergence turned out to be a property of where you dig, not of how long you keep digging.
And a dry well is the good ending. A safety layer that can tell you exactly what it cannot see is worth more than one that promises to see everything, because you can build the next layer on top of an honest edge. The water stopped because we hit the bottom, the bottom has a name, and the name is written next to a rule.
If the check can’t see it without running it, the check is done.