The audit log that can't lie, even to its owner

Engineering · July 2026 · by the person who could otherwise quietly edit it

Every SaaS says "we have audit logs". Almost none can answer the harder question: what stops YOU from rewriting them? Here is how Keyline makes its own audit history tamper-evident, and then puts the proof where we can't touch it.

The problem with trusting the logger

An audit log is a table the vendor writes to. The vendor can also UPDATE and DELETE. So "we log every access" really means "trust our ops discipline and our intentions, forever". For a secrets manager, where the log answers "who read the production credentials and when", that is not good enough. We wanted a design where a rewritten history is detectable by the customer, with no trust in us required.

Layer 1: a hash chain

Every audit event in a workspace carries a sequence number and a hash that covers both its own content and the previous event's hash:

// simplified from the actual implementation
hash(n) = SHA-256(
  prev_hash(n-1)
  || seq || action || actor || target || outcome
  || metadata || created_at
)

Edit any historical event and its hash no longer matches. Delete one and the chain has a hole. Reorder and the links break. Verification walks the chain from genesis and either says "intact" or names the exact sequence number where history diverges. Anyone on the team can run it:

$ keyline audit --verify
Chain intact: 1,204 events verified.

Layer 2: the attack a chain can't stop

Here is the honest limit of hash chains, usually left out of marketing: the operator can rewrite the whole chain. Recompute every hash from the edited event forward, and the forged history is internally consistent. Verification passes. This is not theoretical; it is exactly what a compromised or compelled vendor would do.

You cannot fix this with more cryptography inside the same database. The chain's head has to leave the building.

Layer 3: public anchoring

Once a day, a job takes each workspace's current chain head (the latest hash) and publishes it to a public git repository. Two details matter:

Verification now checks both layers: the chain must be internally intact and its head must match the last published anchor:

$ keyline audit --verify --json
{ "ok": true, "count": 1204, "anchor": { "matches": true } }

Now the wholesale rewrite fails: forged history either breaks the chain, or carries a head that contradicts a public record we cannot retract. The trust equation flips from "trust the vendor" to "catch the vendor".

What this costs

Honesty section. The anchor granularity is daily, so a same-day rewrite before anchoring is theoretically clean; we accept that window at our size (and events within the day are still chained). The anchors repo is a single public witness today; adding a second independent witness (a transparency log, a different host) is the obvious next step. And none of this protects the secrecy of your values; that is the job of the zero-knowledge encryption layer, where secrets are sealed on your machine before upload.

Why bother, at three people?

Because "we can't read your secrets and we can't rewrite your history" are claims a one-person company can make verifiable, and verifiability is the only currency a small vendor has. The design doc, the source, and the anchors are public. Read them, don't trust us.

Discuss: the source · the encryption design · support@keyline.sh

Two minutes to the first encrypted push

$ curl -fsSL keyline.sh/install | sh

Solo is free forever. Team is $19 flat for up to 10 people, 14-day trial.

See the whole journey

No card for Solo. Your secrets are encrypted before they leave your laptop.