WORM audit logs for SaaS
WORM audit logs for a SaaS are tamper-evident activity records your application appends but can never rewrite, enforced by storage, not app convention. Caisson's @caisson/audit-worm gives each tenant a hash-chained log and mints a write-once S3 Object-Lock anchor on every append, so a single call from a request handler records the event and its integrity proof together.
In code
// One store per process; each request appends under the caller's tenant id.
const audit = new AuditChainStore({ db, store: s3WormStore });
// In a request handler — one call records the event AND mints a fresh WORM anchor,
// both inside the same tenant-scoped transaction (never a separate anchoring job).
const { entry, anchor } = await audit.append(accountId, {
action: "invoice.exported",
actor: session.userId,
target: invoiceId,
});
// A truncate-then-replay for entry.seq collides on the write-once anchor key -> ConflictError.How it holds
One call, two independent guarantees
append() writes the chain entry and mints the length-keyed WORM anchor over the result before it returns, in the same transaction. You never run a separate nightly anchoring job that could be skipped, and the DB grant (no UPDATE/DELETE) and the write-once object are two controls, so neither has to hold alone.
Tenant-scoped by construction
Every append runs inside withTenant behind a per-tenant advisory lock, so a forgotten tenant filter can't cross-write another tenant's chain and two concurrent appends can't fork the chain at the same length.
Real WORM storage, not a boolean
The store is an S3 Object-Lock bucket (a local write-once store in dev); the anchor lands via a conditional write-once PUT, so a truncate-then-replay hits the existing immutable object and throws ConflictError instead of silently overwriting the tip.
A six-year retention floor by default
Each anchor carries a retain-until date computed from the audit-worm retention default (seven years, above the six-year floor HIPAA §164.316(b)(2) and SEC 17a-4 set), and retention only ever extends, evidence can't be disposed early.