The audit log that can't lie, even to its owner
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:
- Privacy: the repo is keyed by SHA-256 of the workspace id and contains only hashes. The public learns nothing about who you are or what happened, only that a specific history existed at a specific time.
- Independence: git history on a public host is itself tamper-evident and widely mirrored. Rewriting our database is easy for us; rewriting yesterday's commit in a public repo without anyone noticing is not.
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.
Two minutes to the first encrypted push
Solo is free forever. Team is $19 flat for up to 10 people, 14-day trial.
See the whole journeyNo card for Solo. Your secrets are encrypted before they leave your laptop.