The hash chain we ship — why your audit log can't be tampered with

· IsoKron team · 3 min read

Per-tenant chain heads, RFC 8785 JCS canonicalization in the application layer, hourly Merkle anchors to immutable storage. The architecture that lets us promise an audit log that's evidence, not just record.

  • security
  • audit
  • foundation

Why audit logs matter for AI codegen

Most software-engineering audit logs are written for compliance auditors who'll read them once per year. They're verbose, slow, and impossible to verify after the fact. The author who wrote them is the same author who could quietly change them.

AI codegen needs a different shape. When an AI agent makes a decision that affects production code six weeks from now, you need to be able to walk back to the moment the decision was made, see the context the agent had, see the alternatives it considered, see the model and prompt version. And you need to know nobody — not your engineer, not us, not a malicious actor with database access — quietly edited that record after the fact.

That's what hash-chained audit gives you. Every significant action emits an event into an append-only log. Each event includes the hash of the previous event in the same tenant's chain. Editing an event invalidates the chain from that point forward. You can verify the chain in 60 seconds against an external checkpoint we publish to immutable storage every hour.

How the chain works

Every audit-log row carries:

  • A monotonic per-tenant sequence number
  • The event type from a canonical taxonomy
  • The event-specific payload, AND the same payload canonicalized via RFC 8785 (JSON Canonicalization Scheme)
  • The hash of the previous event in this tenant's chain
  • A SHA-256 hash of this event's payload + envelope + prev_hash
  • A request nonce that defeats replay

The hash envelope is domain-separated to prevent length-extension and concatenation attacks. Every row's hash is computed in the application layer (not in the database) — the JCS implementation is byte-stable across database major versions, which means the chain remains verifiable through infrastructure upgrades. This single discipline is load-bearing.

The audit log is structurally append-only: the database roles that own normal application writes are explicitly revoked from INSERT, UPDATE, and DELETE on the audit table. The only way to add a row is through a privileged function that builds the next link in the chain. The only way to modify a row is no way. The only way to delete a row is no way. The data shape itself rejects tampering.

Verifying yourself

Customers can verify their own chain at any time. Verification walks every event in a tenant's chain, recomputes each hash from its payload + envelope + prev_hash, and returns the first mismatch — or a green pass for the whole chain.

For external verification, we publish hourly Merkle root checkpoints to immutable cloud storage with object-lock in compliance mode (multi-year retention, irrevocable). Each checkpoint is signed with a rotating signing key. The full audit trail looks like this:

  • You verify your in-database chain (no platform trust required)
  • You compare your chain's hourly root against the published external checkpoint (no platform trust required)
  • You verify the external checkpoint's signature against the published public key (no platform trust required)

There is no point in the chain where you have to trust IsoKron's claim that "the data is unchanged." The verification is structural.

Recovery story

The audit chain is also the substrate for disaster recovery. Point-in-time recovery restores the database to any timestamp within the retention window. After restore, chain verification runs against every tenant's chain in parallel. If verification passes, the database is good. If verification fails for a specific tenant, we know exactly which events are affected and can replay or repair them from the external checkpoint trail.

A small CLI restore tool encapsulates the full recovery procedure end-to-end. Worst case for an event whose underlying storage was unrecoverable: that event is marked as lost during recovery in the inventory, the chain remains valid through the loss, and you get an audit-trail explanation of what was lost and why.

The whole story takes minutes, not days.

Bottom line

If you're building serious software with AI, the audit log is part of the trust posture. The standard pattern — a single audit table the platform writes to, that the platform also controls — is fine for compliance but doesn't actually prove anything. Hash chains with external checkpoints and customer-side verification close the gap.

IsoKron ships this as substrate, not as a feature. Every significant action — declaration ingest, compile start, customer review, ticket dispatch, ticket completion — goes through the chain. We don't get to bypass it. Neither do you. That's the point.

Related: The four-layer tenant isolation we ship, BYOK economics.