Audit logs

An audit log that survives its own audit

A mutable log is a comfort, not a guarantee. We chain every event to the previous one with a SHA-256 hash, so altering a single record breaks every record after it. A verifier you can run yourself confirms the chain in O(n). Tampering is no longer a thing you have to detect — it is a self-evident, mathematically demonstrable fact.

Executive summary

Every action — login, seal, role change, document access — is recorded with a SHA-256 hash linking it to the previous event. Verification walks the chain in O(n) time. Customers can export the chain and run the verifier themselves; integrity is independent of our infrastructure.

On top of the chain we layer 7 prebuilt compliance reports, JSON and CSV export, draft → approved → immutable workflow, and per-organization retention policies. Reports lock their content hash on approval; later edits create new versions, never silent revisions.

Our commitments

Five rules for the audit log

01

Tampering is mathematically detectable

Modifying one event in the middle of history requires recomputing every event after it. The verifier returns the exact sequence number where divergence occurs.

02

The verifier is open code, not a trust statement

Chain integrity is checked by a deterministic Elixir function whose source is in this repository. Run it yourself against an exported chain.

03

Approved reports are immutable

Compliance reports go through draft → approved. Once approved, the report's content hash is signed and cannot be silently edited.

04

Every event has actor, action, time, and source

No 'system' actors without explicit cause. No 'automated' without the worker module name. Attribution is non-optional.

05

Retention is your decision, not ours

Each org sets its own retention policy. Default is 'keep forever' — sealing creates a professional record we treat as such.

Implementation — the chain

How the chain is built and verified

Hash algorithm SHA-256 NIST FIPS 180-4
Chained surface hash(prev || canonical_event) Canonical = sorted JSON encoding; deterministic across runtimes
Storage audit_logs table prev_hash, current_hash, sequence_number columns; indexed by org
Insertion ordering Serial within org Verifies linear consistency without distributed coordination
Verifier Credo.Enterprise.Audit.AuditChain Pure Elixir + Erlang :crypto; sequential chain walk with parallel per-record hash via Task.async_stream
Verification cost O(n) Linear in event count; full org chain verifies in seconds
Independent verification Export + run verifier locally Customer can verify against an exported chain without contacting us
Tamper evidence First broken link Verifier returns the exact sequence number where divergence occurs

Implementation — reports

Seven prebuilt reports for your auditor

Activity summary Aggregated event counts Per actor, per action, per org, per time window
Access audit Who accessed what, when Document and credential access trail with IP and device
Document lifecycle Per-document timeline Upload → seal → views → revoke; with full metadata
Credential status Per-credential timeline Verification source, renewal events, status transitions
Security incidents Anomaly events New devices, geo changes, failed MFA, session revocations
Data retention What we still hold Per-record retention basis; pending deletions
Integrity verification Chain verification result Pass/fail with the first divergence sequence number if any

The full picture

What is built, what is being built, and what we chose not to build

Live today

SHA-256 hash chain

Live

Pure-Elixir verifier; O(n) over the org's event log.

Per-event metadata: actor, IP, UA, target, before/after state

Live

No silent system actors. Every event traces to a who and a why.

Audit log export (JSON + CSV)

Live

Self-service export for your SIEM or auditor; includes the chain hashes for independent verification.

Seven prebuilt compliance reports

Live

Activity summary, access audit, lifecycle, credentials, incidents, retention, integrity.

Draft → approved → immutable report workflow

Live

Approved reports lock their content hash; later edits create new versions, never silent revisions.

Per-organization retention policies

Live

Configurable per-event-type retention; auto-archive on schedule; never auto-delete below policy minimum.

Building now

Periodic chain anchoring to an external TSA

Building now

Daily snapshot of the chain head signed by an RFC 3161 TSA. Anchors the chain to a third-party clock so we cannot rewrite history even if we wanted to.

Same TSA pipeline as document seals; reuses verified infrastructure.

SIEM streaming via signed webhooks

Building now

Real-time event push to Splunk, Datadog, Sumo. HMAC-signed, replay-protected.

Field-level encryption for sensitive event metadata

Building now

High-sensitivity payloads in audit events get a second AES-256-GCM wrap so partial database read does not leak them.

Roadmap

Custom report builder

Roadmap

Org admins define their own report shapes alongside the prebuilt seven. Same draft → approved → immutable lifecycle.

Cross-organization log federation

Roadmap

Enterprise customers with multiple EngineeringID orgs get a federated view across them, with per-org access controls preserved.

Continuous compliance dashboards

Roadmap

Real-time dashboards mapped to specific control IDs (SOC 2 / ISO / HIPAA) showing live evidence collection per control.

Considered & rejected

Blockchain-anchored audit log

Considered & rejected

A chained SHA-256 plus a periodic TSA anchor gives the same tamper-evidence at zero per-write cost.

Why we rejected it: blockchain optimizes for "no trusted third party exists." We have public TSAs that already provide the trust property — at a fraction of the latency and at zero per-write cost. RFC 3161 is the eIDAS / 21 CFR Part 11 / common-law-evidence answer to "prove this was unmodified at this time."

Append-only file-based logs without a chain

Considered & rejected

Append-only filesystems are append-only until they are not.

Why we rejected it: filesystem-level append-only is a property of one storage system. A SHA-256 hash chain is a mathematical property of the data, independent of the storage system. We use the latter; storage hardening is defense in depth on top.

Compressing duplicate events

Considered & rejected

A '10x clicked the same button' rollup looks tidier and obscures attack signal.

Why we rejected it: failed-MFA events especially must be recorded individually. Aggregation is what the report layer does — it does not rewrite the underlying log. The log is dense on purpose.

Skipping the chain in dev environments to save cycles

Considered & rejected

Code that runs differently in dev than in prod is the source of every 'it worked locally' production incident.

Why we rejected it: the chain runs everywhere. The performance argument was "save 50ms across an entire test suite," and the risk was "production-only code paths." Hard no.

Compliance mappings

Controls this surface satisfies

SOC 2 CC7.2

Anomaly Detection

Hash-chained event log with first-divergence reporting

SOC 2 CC7.3

Evaluation of Security Events

Seven prebuilt reports map directly to evaluation evidence

ISO 27001 A.12.4.1

Event logging

Per-event actor, action, time, source — chained for integrity

ISO 27001 A.12.4.3

Administrator and operator logs

Privileged actions are first-class events with full payload

HIPAA §164.312(b)

Audit Controls

Hardware, software, and procedural mechanisms to record activity

21 CFR Part 11 11.10(e)

Audit trail — secure, computer-generated

Tamper-evident chain with attribution; export retains integrity

GDPR Art. 30

Records of processing activities

Per-record processing log; retention configurable per data category

SOX §404

Internal control over financial reporting

Tamper-evident change records for financially significant operations

For compliance teams

Questions you do not need to call to ask

Can an EngineeringID employee modify the audit log?
Not without breaking the chain. Database write access exists for operations; any modification to a past record causes the verifier to fail at exactly that record's sequence number on the next pass. Verification runs automatically on every report generation.
Can we run the verifier ourselves against an exported log?
Yes. The verifier source (pure Elixir + Erlang `:crypto`) is in this repository. Export produces a JSON file containing every event plus the hash chain. The verifier returns either 'valid' or the sequence number of the first divergence.
What's the smallest tamper that produces a detection?
A change to any chained field (organization, user, action, resource type, resource id, sequence number) of any record breaks the chain at that record. See Credo.Enterprise.Audit.AuditChain.compute_record_hash/7 for the exact field set. The chain treats those fields byte-for-byte; cosmetic changes elsewhere (resource_name, metadata) are recorded but not yet part of the chained hash — that v2 surface is on the roadmap.
What's the retention default and can we change it?
Default is 'keep forever' because sealing creates a professional record. Org admins can configure shorter retention per event type within the limits set by your active compliance frameworks.
Are reports themselves tamper-evident?
Approved reports have their content hash signed and stored. A modified report becomes a new version with a new hash and a draft state — it cannot quietly replace an approved one. Auditors verify the report hash matches the approved hash they received.
Do you support real-time SIEM ingestion?
Webhook streaming to your SIEM is in active development; same hardening as the API webhook surface (HMAC-SHA256 signing, replay protection, exponential-backoff retry). Today, polled export covers most SIEM ingestion patterns.
What's covered in 'access audit' reports?
Per-actor view of every document and credential access event in the time window: document_viewed, document_downloaded, credential_viewed, with source IP, device fingerprint, and session metadata.

An audit log your auditor can run themselves

Export the chain, run the verifier, see the result. No trust required, only math.