Most teams treat “audit logging” as an afterthought: pipe everything into a SIEM or a big Elastic cluster, then hope the auditor is satisfied. In practice, that’s where the pain starts.
I’m Qin Kang, and I built Log Audit Platform after watching a client burn roughly six engineering-months duct-taping Splunk + spreadsheets together for an ISO 27001 audit. The result was expensive, fragile, and the auditor still asked the one question that sinks most log pipelines:
“How do I know these logs weren’t edited after the fact?”
This post walks through how we designed an audit log that an auditor can actually trust — without sending your data to a third party.
1. Why auditors don’t trust raw logs
A raw log file is just text. Even if it’s shipped to a “secure” bucket, nothing cryptographically ties one line to the next. An attacker (or a well-meaning operator) who gains write access can quietly rewrite history:
- Change a
DELETEinto aREAD. - Backdate an event.
- Remove the record of a privilege escalation entirely.
When an auditor asks “can you prove this wasn’t altered?”, a raw log answers with trust me. That’s not good enough for SOC 2 (CC7.2 / CC8.1) or ISO 27001 (A.8.15 / A.8.16).
The fix isn’t “more storage”. It’s integrity by construction.
2. What SOC 2 and ISO 27001 actually want from logging
Stripped of jargon, the control families want three things:
- Completeness — you captured the events that matter (auth, admin actions, config changes, data access).
- Integrity — a record, once written, can’t be silently changed.
- Availability for review — an auditor (or your own security team) can independently verify both of the above.
Notice the word independently. SOC 2 and ISO 27001 auditors don’t just take your word for it; they want evidence they can re-run. That’s the design goal we optimized for.
3. Hash-chain design: why a sequential hash works for audit logs
Instead of storing events as isolated rows, every record carries the hash of the previous record’s hash chain. Conceptually:
record[0].hash = H(payload[0])
record[n].hash = H(payload[n] || record[n-1].hash)
Enter fullscreen mode Exit fullscreen mode

If an attacker tampers one record, its hash changes and every subsequent link fails verification — the auditor sees exactly where the chain breaks.
Verification walks the chain from the oldest record to the newest. If any payload was altered — even a single character — the recomputed hash at that link no longer matches the stored hash, and every subsequent link breaks too. The verification report marks exactly where the chain was broken.
Why a simple sequential chain rather than a full Merkle tree? For an audit log, records are append-only and verified in order, so a linear chain is simpler to verify, easier to explain to an auditor, and has no reconstruction complexity. (We’re looking at optional RFC 3161 timestamp anchoring as a future external-WORM option, but the in-chain integrity is the core.)
The practical takeaway: editing one record is mathematically impossible to hide.
4. GDPR right-to-erasure without breaking the chain
GDPR’s right to erasure (Art. 17) collides with an immutable log: you can’t just DELETE FROM audit_log a user’s rows, because that breaks the chain and the audit trail.
Our approach is cryptographic erasure / anonymization, not physical deletion:
- Personal data is stored in a separate, keyed store, referenced by token from the audit record.
- On a valid erasure request, we destroy the key material for that subject. The audit record remains (required for the integrity trail), but the linked identity becomes unrecoverable ciphertext.
- The hash chain stays intact, because we erase the key, not the log.
This satisfies both sides: the regulator gets erasure; the auditor keeps a verifiable timeline.
5. Evidence pack automation: turning logs into auditor-ready ZIPs
The second thing auditors hate is hunting. They don’t want your raw database; they want the control mapped to the evidence.
So we ship evidence packs: pre-built, exportable bundles that map collected events to specific control IDs (e.g. SOC 2 AC-2, ISO 27001 A.8.16). One click produces a ZIP containing:
- The relevant filtered records.
- A hash-chain verification report (proving the bundle itself is intact).
- A control-to-evidence mapping sheet.
The auditor runs the verification themselves. No spreadsheet gymnastics, no “trust me”.
6. Self-hosted deployment: one JAR
Compliance data shouldn’t leave your perimeter. Log Audit Platform runs self-hosted:
- Backend: Spring Boot 3 + Java 17+
- Frontend: Vue 3 admin UI, embedded in the build
- Storage: PostgreSQL
- Shipping: a single runnable JAR + Docker Compose
No vendor backend, no telemetry pipe, no API calls home after activation. It runs in your VPC, on-prem, or air-gapped. For teams that can’t use a cloud SIEM for regulatory reasons, that’s the whole point.
7. Pricing: one-time license, not a per-seat SaaS tax
SIEM pricing scales with ingest volume and seats — exactly the metrics that go up when you start taking compliance seriously. We priced it as a one-time license:
- Single — $199 (one instance)
- Business — $699 (up to 5)
- Enterprise — $2,499 (full source + white-label + OEM)
Optional annual maintenance for updates. No per-seat tax, no surprise overage bills right before your audit.
Try it
If you’re preparing for a SOC 2, ISO 27001, or GDPR audit and want an audit log that auditors can verify independently, take a look:
I’d genuinely like feedback from security engineers and compliance folks — what logging controls have been the biggest pain in your audits? What would make you trust a self-hosted log like this one?
Qin Kang — independent developer, building self-hosted compliance tooling.