A tamper-evident log is not a log you promise not to edit. It is a record where an edit shows. That distinction is the whole game. Access controls try to stop the edit. Tamper evidence assumes the edit happens anyway and makes it visible after the fact, to someone who does not trust your storage.
We argued the case for this in an earlier post on why AI agent logs are not enough. That post covered the gap: a plain log records a claim, it does not prove one. This post is about the machinery that closes the gap. How a signed agent record is built, and what actually happens to it when someone tries to change it.
What tampering looks like
Start with the adversary, not the feature. Suppose an AI agent moved money, deleted a record, or approved something it should not have. Someone now wants the audit trail to say otherwise. They have four moves.
- Edit a field. Change the amount, the destination, the timestamp, or the policy decision on a stored record.
- Delete a record. Remove the row that shows the action happened at all.
- Reorder records. Shuffle the sequence so a later action looks like it came earlier.
- Backdate. Insert a record and claim it was written hours or days before it really was.
Each move needs its own defense. A signature catches the edit. A hash chain catches the delete and the reorder. An external anchor catches the backdate. Below is how each one works on an Asqav receipt.
Signed receipts: catching the edit
Every agent action produces a receipt. Before the action runs, Asqav serializes it, evaluates it against policy, and signs the result with a private key. The signature covers the exact bytes of the record. Change a single field later and the signature no longer matches those bytes. Anyone holding the public key sees the failure.
The signature algorithm is ML-DSA-65, Level 3 and widely recommended for most applications, defined in NIST FIPS 204, the module-lattice signature standard NIST published in 2024. It is post-quantum, which matters because agent audit trails carry long retention windows and a signature written today needs to stand up years from now. The point for tamper evidence is simpler though: the signed bytes are fixed at signing time, and no edit to them goes unnoticed.
Why the bytes have to be canonical
There is a subtlety here. The same record can be written many ways. Keys in a different order, extra whitespace, a number formatted two ways. If the signer and the verifier disagree on which bytes to hash, verification breaks on records that were never touched, and that is useless.
Asqav fixes the byte layout with a canonical form, the JSON Canonicalization Scheme from RFC 8785. Object keys are sorted, strings are preserved verbatim, and floating-point ambiguity is kept out of signed envelopes. One record, one byte sequence, one hash. The signature and every downstream hash are computed over that canonical form, so the same content always lands on the same digest.
The per-agent hash chain: catching the delete and the reorder
A signature protects one record. It does nothing about a record that was removed, because a deleted record takes its signature with it. That is what the hash chain handles.
Each agent has its own chain. Every receipt carries a previousReceiptHash field: the SHA-256 of the prior receipt's canonical bytes. The opening receipt on a chain seeds this field with 64 zeros, a genesis marker that means "no predecessor". From there, each receipt's hash becomes the next receipt's previousReceiptHash, so the records are linked in a single line.
{
"receipt_type": "protectmcp:decision",
"action_type": "payments:transfer",
"agent_id": "agt_trading_bot_01",
"issued_at": "2026-07-06T10:30:00Z",
"previousReceiptHash": "9f2c...prior receipt canonical SHA-256...",
"policy_decision": "permit"
}
Now the delete costs the attacker. Remove one receipt and the next one's previousReceiptHash points at a hash that nothing produces anymore. The link dangles. Reorder two receipts and the same thing happens: the chain expects one predecessor and finds another. A verifier walking the chain sees the break at the exact record where it happened.
Asqav also tells apart a real break from an expected one. When a previous_hash points to a record owned by a different agent, the verifier labels it cross_agent rather than tampering, so an operator reading a report knows which links are structure and which are damage.
The rule that makes it hold: re-derive, never trust the stored hash
Here is the mechanic that ties the rest together, and it is the one people miss. A naive integrity check compares two stored values: the hash column on this row against the hash column on the next. An attacker who can edit a field can also edit that column. Rewrite the record, recompute its hash, write the new hash into the column, and a stored-versus-stored check passes.
Asqav does not do that. Every verifier re-derives the hash from the canonical bytes of the record and compares the fresh result against what the chain expects. The stored hash column is never trusted as the source of truth. So editing a field and rewriting its hash does not help: the re-derived hash reflects the edit, and it no longer matches the value the next record committed to. The same holds for the anchor commitment, which is always recomputed from the receipt message rather than read back from a stored column. Tampering that would slip past a stored comparison surfaces here.
This is the difference between a log that claims to be immutable and a record that proves it. The proof does not depend on the database behaving. It depends on math the verifier runs itself.
External anchors: catching the backdate
Signatures and chains keep the record internally consistent. They do not, on their own, prove when a record was written. An attacker who controls the whole store could rebuild a fresh, internally consistent chain and claim it is old. That is where an outside witness comes in.
Asqav anchors each receipt to a public timeline at the moment it is issued. Two anchor types are supported: an OpenTimestamps proof committed to the Bitcoin blockchain, and an external timestamp from an RFC 3161 time-stamping authority. Both commit to the receipt's bytes, and both are re-verified against those bytes at check time, not taken on faith that a log entry exists somewhere.
A backdated record cannot produce an anchor that predates it, because the public timeline it would need to appear in had already moved on. The anchor is the part of the proof that no single party, including Asqav, can quietly rewind.
Transparency logs: a third party that remembers
Anchors prove time. A transparency log adds an independent record that a receipt existed and was seen. Asqav can export a receipt as a COSE_Sign1 structure signed by the same ML-DSA-65 key, in a form a transparency service built on the IETF SCITT work can ingest. We covered that export path in detail in the post on ML-DSA receipts in COSE for SCITT transparency services.
The value for tamper evidence is the second witness. Your own store says the receipt exists. A transparency service, run by someone else, says it saw the same receipt. To make a tampered record look real, an attacker would now have to alter both, and the second one is not theirs to touch.
What the evidence proves, and what it does not
Tamper evidence is worth having because it is honest about its own limits. A cryptographically valid receipt tells you who signed what, and that the bytes have not changed since. It does not tell you the action was safe, correct, or wise. It does not tell you nothing bypassed the signer.
Asqav makes that boundary explicit. A receipt can be paired with a signed appraisal that reports what verification actually confirmed, grouped by axis: authorship, provenance, transparency, and policy. The appraisal carries a fixed list of things it does not assert, including action safety, complete mediation, and key non-compromise. There is no single trusted or valid flag, because a valid signature is not a verdict on the decision it records. An audit stands on evidence that knows what it is, not on a green checkmark.
Putting it together
Tamper evidence for an agent record is four mechanisms doing four jobs. The signature over canonical bytes catches the edit. The per-agent hash chain catches the delete and the reorder. The external anchor catches the backdate. The transparency log adds a witness that is not you. And the rule underneath all of it is that verification re-derives every hash from the bytes instead of trusting a stored value, so the proof holds even when the storage does not.
If you want the field-level detail, the documentation walks through the receipt format, and the logs are not enough post covers why plain logging leaves that gap open to begin with. Or create a free account and sign an agent action today.