Verify the evidence without trusting us.
A published format, a signed example export, and a verifier that is one Python file using only the standard library — no network, no configuration, no B5 dependency. Twenty-one checks. Then change one character and watch it refuse.
What is published today, and what is roadmap. The format specification, the verifier and both example exports are on this page and you can run them now. The in-product export that produces these files from a live B5 deployment is a Q4 2026 roadmap extension, which is what the badge above refers to. The format is deliberately independent of that schedule — an audit firm or SIEM vendor can build against it without B5 software.
The demo is three commands, and you run them
$ python3 b5verify.py ./example-export-ed25519 b5verify — ./example-export-ed25519 ok every record carries the required fields ok every record hashes to its stated digest ok the hash chain is unbroken ok sequence numbers are contiguous and in order ok the manifest's declared head is the last record's hash :: manifest 281e0ac6b700, actual 281e0ac6b700 ok the chain head is signed by the key the manifest names :: ed25519 ok every record states whether it was a simulation ok NOTE: 1 of 5 records are shadow decisions and did not affect any response VERIFIED — 21 checks passed. # exit 0 $ sed -i 's/AC-77310/AC-99120/' example-export-ed25519/records.jsonl $ python3 b5verify.py ./example-export-ed25519 FAIL every record hashes to its stated digest :: [(2, 'ev-01J8ZA', 'stated 5a7c1ab486cd, computed 581ebbefff4f')] VERIFICATION FAILED — 1 of 21 checks did not pass. # exit 1
Exit 0 verified, 1 failed, 2 unreadable — so it composes into a pipeline. There is no hosted service to be up, no account to create, and nothing of ours to trust.
The chain, and the flaw the attack suite found
The most useful thing on this page, because it is an argument against our own first draft.
Each record’s digest is:
hash = SHA-256( canonical_body ‖ "\n" ‖ prev_hash ‖ "\n" ‖ sequence )
The first version of the format excluded the whole decision_evidence block from each record’s digest. That is reasonable on its face — a digest cannot cover itself — but it left prev_hash and sequence uncovered. A record’s hash therefore depended only on its own body.
So the chain could be relinked. Alter record 2, recompute its hash, re-point record 3’s prev_hash, and the chain verified cleanly. The head only moved if the last record changed, so the signature still passed. Tamper case 05 passed when it should have failed. Binding the linkage into the digest means a tamper is caught by that record’s own hash — and an attacker who recomputes it to hide the change then finds every subsequent hash must change too, which moves the head, which breaks the signature. There is no longer a repair that relinks cleanly.
A format specification that has not been attacked is a draft. This one would not have been found by writing the spec and admiring it.
Nine attacks, all rejected
Flip a denial to a permit
Caught by the record hash.
Delete a record mid-chain
Caught three independent ways — count, chain and sequence — deliberately, so repairing one is not enough.
Reorder two records
Caught by sequence and by the chain.
Tamper, then fix that record’s own hash
Breaks at the next record.
Re-chain after a tamper
Head moves; head signature fails.
Forge the head signature
Fails against the public key.
Move a record outside the window
Caught against the manifest window.
Strip the shadow flag
Rejected — shadow status is mandatory, not defaulted.
Re-chain an ed25519 export without the private key
Impossible by construction; that is the point of the second export.
Two example exports, and the honest reason for both
HMAC — deliberately forgeable
Signed with HMAC-SHA256 with the secret in the manifest, so it verifies using the standard library alone. That also makes it demonstrably forgeable, and we would rather say so than let you discover it.
Public key only — production
The manifest carries the public key and nothing else. This is the shape a real export takes.
Shipping only the convenient one while claiming signatures protect the chain would be a claim the artefact itself contradicts. And when the signing library is absent the tool reports the signature check as SKIPPED, never as passed — a verifier that silently downgrades is worse than one that refuses.
{
"format": "b5-evidence/1",
"generated_by": "B5 Security Platform 4.0.0.3",
"tenant_uid": "t-8f21c0",
"records": "records.jsonl",
"record_count": 5,
"window": {
"start": 1785225600123,
"end": 1785225605222
},
"canonicalisation": "JSON, sorted keys, separators (',',':'), UTF-8, with the decision_evidence block excluded from its own digest",
"chain": {
"uid": "chain-t-8f21c0",
"head_hash": "281e0ac6b7008233b00a0edff683b19f0b1c4c30a6e48b7197953ac32fed8d28",
"signing_key_uid": "key-2026-07-ed25519",
"signature": "22VwTgPGqQxoRIfGb0w22Yg56hPjgeRH7wqSEipFy+d5J2Jm8EledjLCM9ea6g6gL709qRxfJPrnt/qIcdxCCA=="
},
"key": {
"uid": "key-2026-07-ed25519",
"alg": "ed25519",
"public_b64": "hdTepOHcEpC9nRgdvrSf2eYbJgWFSsMM0JOg7xvDfBA=",
"_note": "Public key only. The private key never leaves the signer."
}
}Give it to your auditor during the evaluation
Not after contracting. The format and the tool are yours to keep either way, and neither depends on us continuing to exist.
Talk to a human.
Get architecture guidance, Test Mode access, integration review, or help choosing the right B5 identity and authorization pattern.