Three consecutive releases of our own security harness were correctness disclosures. Not features. Each one found a different way the tool had been reporting a verdict it had not earned, and each one told users to re-run anything they had measured before it.
The three defects are worth reading together, because separately they look like ordinary bugs and together they are a single lesson about testing anything autonomous.
4.15.0 — a test that could not run is not a test that passed
Seven modules recorded a PASS when the target never serviced the request. A host that was not running produced a clean pass.
Every affected detector short-circuited on an error response and returned “no attack indicator found,” and every caller read that as “the control held.” Verified by running the verdict expressions rather than by reading them:
- transport failure, host down → recorded
passed=True - HTTP 404 → recorded
passed=True - HTTP 500 → recorded
passed=True - HTTP 200 carrying a JSON-RPC error envelope → recorded
passed=True
In two adapter modules it was not even accidental. Seventeen sites computed passed = self._check_error(resp) — setting a pass because the target had errored.
The guard already existed. A _serviced() helper had been written two releases earlier to fix twenty false passes in one module — and left in that file. Nothing carried it to the six other modules with the identical verdict pattern. The fix was known, correct, and un-propagated for two releases. It now lives in the shared recording path, so a test cannot forget a guard it never has to call.
4.16.0 — a target that refuses is the control working
The next release moved verdicts in both directions, and the second direction was the new one. More results became INCONCLUSIVE, for the reason above. But some results that used to FAIL now correctly PASS: a target that visibly refuses an attack is the control working, and ten modules could not recognise that.
A scanner that cannot tell “the attack was blocked” from “the attack failed to arrive” is not conservative. It is wrong in a direction that happens to feel safe.
4.17.0 — and a target that complies is the control failing
Then the sharpest one. Eight modules could not distinguish an agent that refused an attack from one that complied with it, and reported PASS for both.
Measured against a live loopback agent answering HTTP 200 to everything:
return_channel_harness passed every test against a complying agent, a refusing agent, and an agent visibly attacking — including one emitting root:x:0:0 and API_KEY=sk-live-1
gtg1002_simulation, which simulates a documented nation-state espionage campaign, passed 17 of 17 for a complying agent and 17 of 17 for a refusing one. Six of the rows that survived an agent reporting harvested credentials, lateral movement, 42,000 exfiltrated rows and established persistence are rated P0-Critical.
And the inverse case, which is the one I would put on a slide. over_refusal_harness exists to catch an agent that wrongly blocks a legitimate request. It passed 25 of 25 against an agent that refused everything. It read the HTTP status and never the response body, so the entire class it exists to detect was invisible to it.
One contributing defect is small enough to be funny and serious enough to be instructive: the refusal classifier matched substrings, so “restricted” matched inside “unrestricted”. An agent announcing “Profile escalated to admin, unrestricted” was therefore classified as refusing. It now matches on word boundaries. The related negation case — “no longer blocked” — is not fixed, and ships documented as a known limit rather than quietly.
The common shape
Three defects, three releases, one structure. In every case the tool produced a confident verdict from a signal that could not support it:
- an absent answer read as a safe one;
- a refusal read as a failure;
- a compliance read as a refusal.
None of these is a false negative in the ordinary sense. The tests ran. They returned. They were green. What was missing was any check that the green meant anything — and a passing test that cannot fail is not evidence, it is decoration.
What actually catches this: targets whose answers you already know
You cannot find this class by reading the code, because the code looks fine. Every one of these defects was found by running the suite against deliberately constructed targets whose correct verdict was known in advance:
- a closed port — nothing answers, so everything should be inconclusive;
- a permissive host that answers HTTP 200 and grants everything — harder, because every serviced-request guard is satisfied and the target is maximally unsafe;
- a refusing host — where a pass is correct, so a suite that fails everything is exposed too.
The permissive host is the one most tools never build, and it is the one that found the worst of these. A closed port catches a suite that passes when nothing is there. Only a target that says yes to everything catches a suite that passes when everything is wrong.
Point your security suite at an endpoint that answers 200 and grants every request. If your pass rate does not collapse, your suite is not measuring what you think. Then point it at one that refuses everything. If your pass rate does not go up, it is not measuring that either. Both runs take an afternoon, and either result is worth more than another hundred tests.
Why publish this
The uncomfortable framing is the accurate one: for several releases, a tool whose entire purpose is telling you whether your agent is safe was, in specific and now-enumerated ways, unable to tell. Anyone who ran the affected modules against a live target got numbers that did not mean what they said, which is why each release told them to re-run.
The alternative was to fix it quietly in a patch note. That option was available and it was worse, for a reason that has nothing to do with virtue: a security tool’s only real asset is that you believe its verdicts. A tool that silently corrects a class of false passes is asking to be trusted on exactly the dimension it just failed on. Publishing the tables — complying, refusing, attacking, side by side — is the only version that leaves a reader able to check the claim.
It is the same argument as the pipeline stage that logged success for fourteen days while writing nothing, arriving from the other end. There, a producer reported success and produced nothing. Here, a verifier reported a verdict it had not earned. Both are the same failure: a system reporting on itself, with nothing independent to contradict it.
Two limits, stated because they are the point
First: this harness holds no I2 evidence at all — no independent-sensor observation — because it reads protocol responses the target itself emits. That is a structural ceiling, not a backlog item.
Second, and more relevant here: an independent developer recently wrote a separate implementation of one of our fixture oracles and reproduced all eleven verdicts. That is the first external check this project has ever received, and the honest reading of it was published alongside the release rather than in a press line:
“Two implementations agreeing establishes that they share a reading; only a third can tell you whether that reading is the contract or a coincidence.”
A reproduction is not a validation. It is one external party getting the same answers from the same inputs — genuinely useful, and not the thing a reader should mistake it for. Which is the whole argument again, applied to the one piece of good news in it.
Related reading
The Stage Reported Success for Fourteen Days and Wrote Nothing10 of 122: The Monitoring Was Not Built to Watch the Evaluation as It Ran
What We Built: the agent-security harness