Multi-region ledger on Amazon Aurora DSQL

The audit log nobody can rewrite.Not even you.

Indelible is a tamper-evident audit ledger. Every event is hash-chained, and verification recomputes the whole chain from the stored bytes — so a direct UPDATE or DELETE shows up at the exact record it touched. Checkpoints are signed and published outside the database, which means even a full rewrite by someone holding the credentials leaves a trace.

2 regions
one strongly consistent chain
0 trust
verification recomputes every hash
RFC 6962
Merkle checkpoint digests
Ed25519
anchors signed and published
Threat model

Three attacks an insider can run

Assume the attacker holds the database credentials — a DBA, a leaked admin key, a malicious insider. The first two are caught by re-hashing the chain. The third one is not, and it is the reason signed anchors exist.

Edit a record

UPDATE straight against the table, bypassing the app entirely.

Verification re-hashes the stored bytes and fails at the exact seq.

caught: PAYLOAD_HASH_MISMATCH

Delete history

DELETE rows mid-chain, or truncate the newest records.

The chain gaps, or the stream head no longer matches the last record.

caught: GAP / HEAD_MISMATCH

Rewrite everything

Edit a record, then recompute every hash through the head. The chain is self-consistent again — in-chain verification passes.

Checkpoint roots are signed by a key the database role cannot reach and published to a public repo our infrastructure cannot push to. The rewritten history no longer reproduces the anchored root.

caught: FULL_REWRITE
How it works

Append, verify, anchor

Active-active across us-east-1 and us-east-2 on a peered Aurora DSQL cluster: one logical database, strong consistency, and the same chain verifiable from either coast.

  1. 1

    Append

    Events arrive over HTTPS or MCP, are canonicalized (RFC 8785-style JSON), and SHA-256-chained. Aurora DSQL's optimistic concurrency makes the stream head the single contention point — concurrent writers from both regions serialize into one gap-free chain, with conflict-retry that re-chains instead of corrupting.

  2. 2

    Verify

    Verification trusts nothing: it refetches stored bytes and recomputes every payload hash, every link, the genesis anchor, and the head. Auditors run the same check offline with one command — no access to us or our database required.

  3. 3

    Anchor

    Checkpoints pin seq 1..N under an RFC 6962 Merkle root, signed with a key the database role cannot reach. A GitHub Action pulls signed anchors into a public repo on a schedule — publication happens from outside our infrastructure, and the repo's git history is itself append-only evidence.

Measured, not claimed

Serializing a hash chain on Aurora DSQL: the ceiling, measured

One stream tops out near 5.5 appends/s no matter how many writers pile on — then batching lifts the same stream to 182 and independent streams scale it linearly. The benchmark deep-dive, with every run committed to the repo.

Read the deep dive
Integration

Write with a key, verify without one

Scoped API keys per tenant (hashed with SHA-256 at rest, shown to you once). Writing needs a key; reading and verification stay open by design, so anyone can audit the log without asking us for access.

append an event
curl -X POST $BASE/api/streams/$STREAM/append \
  -H "authorization: Bearer $API_KEY" \
  -H "content-type: application/json" \
  -d '{"payload":{"action":"payout.released","amount":129.5},"actor":"treasury-svc"}'
auditor verifies offline — zero trust in us
npm run verify:offline -- --records records.json \
  --anchor anchor.json --pubkey checkpoint-ed25519.pub.pem

Recomputes every hash and the Merkle root locally, checks the anchor's signature against the published public key, and prints the verdict.

It also speaks MCP. An agent can append to and verify the same chain through four region-aware tools — ledger_append, ledger_verify, ledger_checkpoint, ledger_streams. Wire it up locally:

claude mcp add … /api/mcp

Try to break it.

The console has a fenced Danger Zone that runs the raw SQL of a malicious DBA for you — an UPDATE, a DELETE, or a full rewrite. Then hit verify and watch where it lands.

Open the console