Threat model: verification ledger
Scope: the single-file ledger page at ledger/index.html (served at ainumbers.co/ledger/ and ledger.ainumbers.co). Written from the page and its gates on . All threat models.
Assets
- Receipts and artifacts the visitor loads into the page. They can describe business decisions. They are parsed and shown in the tab.
- Verification verdicts. A visitor relies on the page saying a receipt does or does not verify. A wrong "verified" is the worst failure.
- Interface state kept in the browser (see below). Low sensitivity, but it is a stored record on the visitor's device.
Trust boundaries
- Visitor's file or pasted JSON to the page's parser, inside the tab.
- Page to
anchor.ainumbers.co, the only network destination its CSP allows (connect-src https://anchor.ainumbers.co). See the anchor relay model. - Page to the visitor's browser storage (
localStorage) on the ledger origin.
Adversaries
- L1. A crafted receipt file meant to make the page run script or call out.
- L2. A change to the page that adds a second network destination.
- L3. A shared-link recipient or local user who reads what the page stored in the browser.
- L4. A forged receipt presented as genuine.
In scope and out of scope
In scope: egress beyond the one allowed endpoint; what the page sends when the visitor chooses to anchor or request a signature; browser storage contents; verifier correctness against forged inputs.
Out of scope: a compromised browser; the truth of what a receipt's author claimed; the availability of the anchor service.
Controls
| Threat | Control | Where it lives |
|---|---|---|
| L2: extra network call | Gate fails on any fetch(, XMLHttpRequest, WebSocket or EventSource outside the anchor endpoint | scripts/check-ledger-hermetic.mjs |
| L2: wider CSP | The ledger CSP permits connect-src https://anchor.ainumbers.co where the standard profile says 'none'; that is the only network allowance in it | scripts/check-csp-consistency.mjs, CSP meta tag in ledger/index.html |
| L1: remote frames, workers, objects | CSP sets frame-src 'none', worker-src 'none', object-src 'none' | CSP meta tag in ledger/index.html |
| Over-sharing on anchor | The anchor call sends the artifact's execution_hash and the chosen authority name; the artifact stays in the tab | ledger/index.html, the anchor_hash request |
| Over-sharing on escalation | The signature request sends a record hash, a role, and a short message containing the gate step id and the names of halted steps. That text leaves the browser, so step names should not hold confidential wording | ledger/index.html, the create_signature_envelope request |
| Hammering the relay | Client-side cooldown between anchor clicks (a convenience, not a security control); the real limit is server-side | _anchorCooldown in ledger/index.html; see anchor model |
| L4: forged receipt verified | A separate gate holds verification code to zero network egress; this page makes no claim here about how strong the checks themselves are, which the kernel and parity gates cover | scripts/check-verify-no-egress.mjs |
What the page keeps in the browser
The page uses localStorage. It keeps a ledger filter choice, a "demo dismissed" flag, and, per escalation request, a pending entry keyed by the record hash. The site-wide rule that tools use no client storage (CONTRACT.md section 1.1) is a rule for tool pages, and the ledger is the documented exception because its interface state has no server to live on. The privacy policy says the site uses no client-side storage for identity or tracking; this list is the full set we know of.
UNTESTABLE claims
- "Only a hash is sent." True of the anchor request in the source today. The hermetic gate checks where the page may call, not what it sends there.
- Contents of browser storage. No gate lists or limits the keys the page may write.
- A fully hostile receipt file. The CSP contains script and network damage, but no fuzzing gate covers the page's parsers.
Residual risk
- Anyone with access to the visitor's browser profile can read the stored interface state, including pending escalation hashes.
- Inline scripts are allowed by the CSP, so it limits where data can go while script already on the page can still act.
- The page can build a share link with a URL fragment (
ledger.ainumbers.co/#...). Whoever holds such a link may be able to see what it encodes.