Tamper-evident logging via hash chain or digital signatures
Why it matters
An append-only table that cannot be modified by the application is still vulnerable to a privileged database administrator who directly connects to the instance and runs UPDATE or DELETE without going through the application layer. Tamper evidence via hash chains or digital signatures closes that gap — any modification of a stored log entry invalidates the chain and is detectable even after the fact. NIST 800-53 AU-10 (Non-Repudiation) requires that the organization protect against individuals falsely denying having performed particular actions. NIST 800-53 AU-9 requires protection of audit information integrity. PCI-DSS v4.0 Req-10.3.4 requires file-integrity monitoring or change-detection mechanisms on audit logs so existing data cannot be changed without generating alerts — exactly the property hash chains or digital signatures provide. NIST SP 800-92 (Guide to Computer Security Log Management) recommends integrity checking of log archives. CWE-345 (Insufficient Verification of Data Authenticity) is the vulnerability class.
Severity rationale
Medium because tamper detection is a secondary control — without it, a privileged insider can modify log records directly at the database layer and the breach may go undetected indefinitely.
Remediation
Add previous_hash and entry_hash columns, then compute the hash in the logging service in src/services/audit-logger.ts:
import crypto from 'crypto';
async function logWithHashChain(entry: AuditEntry) {
const previous = await db('transaction_logs')
.orderBy('created_at', 'desc').first(['entry_hash']);
const payload = JSON.stringify({
user_id: entry.userId, operation: entry.operation,
amount: entry.amount, timestamp: entry.timestamp,
previous_hash: previous?.entry_hash ?? 'GENESIS'
});
const entryHash = crypto
.createHmac('sha256', process.env.AUDIT_SIGNING_KEY!)
.update(payload)
.digest('hex');
await db('transaction_logs').insert({
...entry,
previous_hash: previous?.entry_hash ?? null,
entry_hash: entryHash
});
}
Store AUDIT_SIGNING_KEY in a secrets manager (AWS Secrets Manager, Vault), not in the application's environment file.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Financial Audit Trail Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- cwe · CWE-345 — Insufficient Verification of Data Authenticity
- nist:rev5 · AU-10 — Non-Repudiation
- nist:rev5 · AU-9 — Protection of Audit Information — cryptographic integrity
- pci-dss:4.0 · Req 10.3.4 — File-integrity monitoring or change-detection on audit logs to alert on any data modification
- nist:final · SP-800-92 — Guide to Computer Security Log Management
Taxons
History
- 2026-04-18·v1.0.0·Initial import from finserv-audit-trail·automated