The audit log as evidence
The last post ended on a rule: the escape count has to be zero, and one escape invalidates a run's safety claim. That is easy to write down. The harder question is how anyone other than me is supposed to believe it.
"Zero escapes" is a claim about every action the system didn't take outside its bounds. Recall is a number you can check against a fixture's labels. A safety claim is a statement about a whole run, and you can only check it if something recorded that run in a way that can't be quietly rewritten. This post is about that record: the audit log, treated as evidence rather than as debug output.
A tool that says "trust me, I found this and I stayed in scope" is asserting, not proving. Trust has to come from a record the tool cannot forge or edit after the fact.
Why self-report isn't evidence
Once a model is in the discovery loop, the tempting shortcut is to ask it. Did you confirm the finding? Did every request stay in scope? The model will answer, fluently and confidently, and the answer is worth roughly nothing as evidence:
- It is generated, not observed. A model's summary of what it did is another output of the same process you are trying to audit. It can be wrong in exactly the cases where you most need it to be right.
- It is unfalsifiable after the fact. "I stayed in scope" with no underlying record cannot be checked by a reviewer. All they can do is believe it or not.
- It is shaped by the goal. A proposer that is optimised to find bugs has every incentive, statistically if not intentionally, to describe a weak signal as a confirmation. That isn't malice. It is just what optimisation pressure does to a self-description.
The same is true of any component reporting on itself, model or not. A logger that the discovery engine can write to, edit, and truncate is just a longer self-report.
Separate the recorder from the engine
The earlier posts in this series kept applying one move: take a decision away from the component that benefits from it. Authorization is minted at a gate the engine doesn't control, and so is scope. The audit log is the same move applied to memory.
- The engine proposes. It can suggest an action, a candidate finding, a confidence. It cannot decide whether that action was allowed, and it cannot set its own verdict.
- The gate decides and records. The gate's allow or refuse decision is written to the log by the gate, not relayed through the engine.
- The log is write-only to producers. Components can append. None of them can read back and modify, reorder, or delete. Nothing in the discovery path holds the signing key.
Separation of powers sounds grand for what is mostly a permissions decision. But it is the difference between "the system says it behaved" and "the system could not have hidden it if it hadn't".
Anatomy of a log you can use as evidence
I think of it as a spine. Every decision the pipeline makes is pinned to it, in order, and the spine itself is what you hand to a reviewer. Three properties make it a spine rather than a text file:
- Append-only. Events are added, never rewritten or deleted. A correction is a new event that references the old one, not an edit.
- Hash-chained. Each entry includes the hash of the previous entry. Change any byte of an old entry and every hash after it stops matching. Delete an entry and the chain has a visible gap.
- Signed. The chain head is signed periodically by a key the engine never sees. A hash chain alone shows that the record is internally consistent. The signature shows who vouches for it and pins the record at a point in time, so the whole chain can't be regenerated from scratch to match a wished-for outcome.
None of this is novel. It is the same idea behind certificate transparency logs and tamper-evident system logging. What is less common is applying it to the decisions of an autonomous security tool, which is exactly where it matters most.
What goes in
The test for content is replay: a reviewer should be able to reconstruct every decision from the log alone, without re-touching a target. For each step that means:
- The proposal: the structured action or candidate the engine put forward, as data, not as the engine's narrative about it.
- The gate decision: allow or refuse, and the rule that produced it.
- What was in force: the scope revision and the authorization
policy version the gate evaluated against, the same
scope_revthe earlier posts put on every minted handle. - The verifier's observation: what it re-observed, the confidence it computed, and the floor it was compared against.
- The verdict: confirmed, not confirmed, or indeterminate, and which component set it.
- Timestamps and linkage: when each event happened and which earlier events it depends on.
Here is the shape of one such entry. It is illustrative only: a hypothetical sketch of the fields, not a real Warren artifact or format.
seq: position in the chainprev_hash: hash of the previous entryevent: e.g.gate_decisionorverificationproposal_ref: reference to the structured proposal being decided onscope_rev,policy_version: what the gate evaluated againstdecision: allow / refuse, plus the rule identifierconfidence,floor: for verification events onlyverdict,set_by: the outcome and the component that set it, which is never the proposerts: timestamp
What stays out
What you leave out matters just as much. An evidence log can fail by holding too much as easily as by holding too little.
- Secrets. Credentials, session tokens, and client certificates live behind the gate. The log records that a scoped credential was used, never its value. An audit trail that leaks secrets becomes a liability you can't hand to a reviewer.
- Model free-text as a verdict. The model's reasoning can be kept as a clearly labelled, unsigned annotation for debugging. It never goes into the verdict field, and it never gets signed as if it were an observation.
- Raw response bodies by default. Store a digest, or a minimal redacted excerpt where the verifier needs it. Full captures of third-party data don't belong in a record whose job is to be shared.
- Anything that lets the record be fitted to the outcome. No "summary" fields filled in after the run, and no rewritten entries. If a later stage changes its mind, that is a new event.
Verification writes only to the spine
This is where the post connects to my own work. My research system, Warren, just gained an autonomous-verification stage, and the audit log is what keeps it honest. At the design level it works like this:
- It re-observes, inertly. The verifier looks again at the candidate's detection signal. It doesn't re-exploit, probe harder, or take any new action against the target. Verification that needs a bigger hammer than discovery used is no longer verification.
- It confirms only above a confidence floor. The floor is fixed in configuration ahead of time, and both the computed confidence and the floor are recorded, so a reviewer can see the margin rather than just the verdict.
- It fails closed. An indeterminate observation is not confirmed. So is any safety-stop signal during verification. There is no "probably" bucket that drifts into the findings list.
- It writes only to the signed spine. The verdict lands in the log through the recorder. The proposer can't set it, can't sign it, and its own claim about the candidate never appears in the verdict field.
The model proposes. It doesn't get to grade its own work, and it doesn't hold the pen that records the grade.
What it buys you
- Reproducibility. Replay the recorded proposals through the gate under the recorded scope revision and policy version, and you should get the same decisions. The last post argued the gate should be a pure function. The log is the input you need to test that.
- Non-repudiation. A signed chain can't be quietly rewritten. If the record says an action was refused, nobody can later claim it was allowed, and the reverse holds too. That cuts both ways, which is the point.
- Review without re-touching. A supervisor, an examiner, a program triager, or a second model can check that the gate held and the floor was met by reading the record. Nobody has to send another packet to a target to audit the run.
It also changes what the claims in this series mean. "Escapes must be zero" from the last post only becomes credible once you can show it: every egress event in the log has a matching allow decision, and every allow has an in-scope revision behind it. Fail-closed verification only counts if each verdict is pinned to tamper-evident evidence. Without the log, both are just intentions.
Ways to get it wrong
Most of these are tempting because they make the log easier to build or nicer to read:
- Logging the model's self-claim ("confirmed, high confidence") as the verdict.
- A mutable log: a database table the engine can
UPDATE, or a file it can rewrite. - Hashing without signing, or signing with a key the engine can reach. Either way the chain can be regenerated end to end.
- Leaking secrets or raw third-party data into evidence, so the record can never be shared.
- After-the-fact edits, even well-meant ones like "fixing a typo" in a decision reason. Append a correction instead.
- Logging only allowed actions. Refusals are half the safety story, and an escape count is only meaningful if the refusals are on the record too.
- Silently dropping log writes under load. If the recorder can't write, the action shouldn't happen. The log fails closed too.
The trade-offs are real. Signing and chaining cost a little latency and some operational care around keys. Redaction means a reviewer sometimes sees a digest where they would like the full response. I think that is the right side of the trade for a tool that acts on systems it doesn't own.
Where this sits in the series
Earlier posts argued that safety has to be architectural, that authorization and scope belong at a gate the discovery engine doesn't control, and that the system should be measured against labelled fixtures with an escape count that must be zero. This post is what turns those rules into something you can check: a write-only, hash-chained, signed record of every decision, which the engine can add to but never edit.
Next in the build log: fail-closed verification in practice. What "inert re-observation" can and can't confirm, and where a confidence floor should come from.
This is part of an open build log for my Master's research on safe automated vulnerability discovery. All experimentation runs against self-owned, authorized lab targets only. More about the research →