Skip to content
Browse documentation

Reference

Audit & verification

Every authorization decision — allow or deny, on every surface — is appended to a hash-chained, tamper-evident log. Read it with GET /v1/audit and prove the chain is intact with GET /v1/audit/verify.

The audit row#

Each decision appends one row. A row records who did what, where, and how it was decided — plus the cryptographic linkage that makes the log tamper-evident.

FieldTypeMeaning
seqintMonotonic sequence number (starts at 1; the genesis row's prev_hash is 0×64).
tsintUnix epoch milliseconds.
principalstringThe acting principal id.
actionstringThe attempted action (e.g. search, ingest, read).
resourcestringThe scope / unit / route touched.
surfaceUI | CLI | REST | SDK | MCPWhich surface the request came through.
decisionallow | denyThe enforcement outcome.
prev_hashstringHash of the previous row (0×64 for genesis).
hashstringsha256 over this row's canonical JSON incl. prev_hash.

How the hash chain works#

The log is a chain: each row’s hash is computed over a canonical (key-sorted) JSON encoding of the row’s fields including the previous row’s hash. Because the encoding is deterministic, anyone holding the rows can recompute every hash. Altering, dropping, or reordering any row breaks the linkage from that point forward.

chain linkage
row.hash = sha256(canonicalJson({ seq, ts, namespace, principal,
                                  action, resource, surface, decision,
                                  prev_hash }))
row[n].prev_hash == row[n-1].hash        (row[0].prev_hash = 0×64 genesis)

List the audit log#

GET/v1/audit

Returns hash-chained AuditRow rows for the caller’s namespace, newest first. Requires read or admin. Supports limit and a cursor (echo back next_cursor to page).

curl
curl -s "https://superchargedb.krisch1218.workers.dev/v1/audit?limit=50" -H "Authorization: Bearer aegis_sk_alice"
200 OK (truncated)
{
  "namespace": "acme-corp",
  "rows": [
    {
      "seq": 2,
      "ts": 1783343567981,
      "namespace": "acme-corp",
      "principal": "bob@acme",
      "action": "read",
      "resource": "u-call-02",
      "surface": "MCP",
      "decision": "deny",
      "prev_hash": "b1946ac92492d2347c6235b4d2611184e2b6f0d9f1c3a2...",
      "hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822..."
    },
    {
      "seq": 1,
      "ts": 1783343567016,
      "namespace": "acme-corp",
      "principal": "alice@acme",
      "action": "search",
      "resource": "acme/alpha/backend",
      "surface": "REST",
      "decision": "allow",
      "prev_hash": "0000000000000000000000000000000000000000000000000000000000000000",
      "hash": "b1946ac92492d2347c6235b4d2611184e2b6f0d9f1c3a2..."
    }
  ],
  "count": 2,
  "next_cursor": null
}

Verify the chain#

GET/v1/audit/verify

Recomputes the chain server-side and reports whether it is intact. This lets any reader — an auditor, a compliance job, or your own CI — independently confirm the log has not been reordered, truncated, or altered.

curl
curl -s "https://superchargedb.krisch1218.workers.dev/v1/audit/verify" -H "Authorization: Bearer aegis_sk_alice"
200 OK — intact
{
  "namespace": "acme-corp",
  "intact": true,
  "checked": 128,
  "head_seq": 128,
  "head_hash": "3fa1c0e2…",
  "break_at": null,
  "reason": null
}

If a row had been tampered with, the response pinpoints the first broken link:

200 OK — broken
{
  "namespace": "acme-corp",
  "intact": false,
  "checked": 57,
  "head_seq": 56,
  "head_hash": "9c2b…",
  "break_at": 57,
  "reason": "prev_hash does not link to the prior row's hash"
}
FieldTypeMeaning
intactbooleanTrue when every recomputed hash matches and links to its predecessor.
checkedintNumber of rows verified before stopping.
head_seqintSequence number of the last valid row.
head_hashstringHash of the last valid row (0×64 for an empty chain).
break_atint | nullThe seq of the first broken row, or null when intact.
reasonstring | nullHuman-readable failure reason, or null when intact.

WORM sealing

The chain head is CAS-committed and periodically sealed into object-lock (WORM) storage, so the log is append-only in storage as well as by construction. See the Security model for how audit fits into the two enforcement layers.

Verified against the shipped contract

The list response is { namespace, rows: AuditRow[], count, next_cursor } and the verify response is { namespace, intact, checked, head_seq, head_hash, break_at?, reason? }, matching the shared @superchargedb/sdk types and the deployed Worker.