{"record":{"id":"5ae5700dc7ce08e3","repo":"zeroclaw-labs/zeroclaw","slug":"entry-hash-mismatch-at-line-sequence-expe","errorCode":null,"errorMessage":"entry_hash mismatch at line {} (sequence {}): expected {}, got {}","messagePattern":"entry_hash mismatch at line (.+?) \\(sequence (.+?)\\): expected (.+?), got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/zeroclaw-runtime/src/security/audit.rs","lineNumber":495,"sourceCode":"                entry.sequence\n            );\n        }\n\n        // Check prev_hash linkage\n        if entry.prev_hash != expected_prev_hash {\n            bail!(\n                \"prev_hash mismatch at line {} (sequence {}): expected {}, got {}\",\n                line_idx + 1,\n                entry.sequence,\n                expected_prev_hash,\n                entry.prev_hash\n            );\n        }\n\n        // Recompute and verify entry_hash\n        let recomputed = compute_entry_hash(&entry.prev_hash, &entry);\n        if entry.entry_hash != recomputed {\n            bail!(\n                \"entry_hash mismatch at line {} (sequence {}): expected {}, got {}\",\n                line_idx + 1,\n                entry.sequence,\n                recomputed,\n                entry.entry_hash\n            );\n        }\n\n        // Verify signature if present and key is available\n        if let Some(ref signature) = entry.signature\n            && let Some(ref key_bytes) = signing_key\n        {\n            use hmac::{Hmac, Mac};\n            use sha2::Sha256;\n\n            let mut mac = Hmac::<Sha256>::new_from_slice(key_bytes).map_err(|e| {\n                ::zeroclaw_log::record!(\n                    ERROR,","sourceCodeStart":477,"sourceCodeEnd":513,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/security/audit.rs#L477-L513","documentation":"The recomputed entry_hash (derived from the entry's prev_hash plus its contents via compute_entry_hash) differs from the entry_hash stored in the line. This means the entry's fields were modified after the record was written — content tampering detected, independent of chain linkage.","triggerScenarios":"Editing a field of an audit line (tool name, outcome, timestamp) with a text editor; sed/regex fixes across the log; a buggy script rewriting lines with serde re-serialization that changes field formatting; memory/disk corruption flipping bytes.","commonSituations":"Operators 'correcting' wrong-looking audit entries; automated redaction scripts that mutate the log in place; partial restores mixing old content with new hashes.","solutions":["Restore the tampered line (or the whole file) from a trusted backup or off-site copy.","Preserve the tampered file for forensics — the mismatch itself is the evidence.","Audit who had write access to the log and tighten permissions (the writer should be the only writer).","Never rewrite audit logs in place; if redaction is required, do it in a derived copy with a documented transform."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(e) = audit.verify_chain() {\n    if e.to_string().contains(\"entry_hash mismatch\") {\n        // content tampering: preserve the file byte-for-byte for forensics and alert\n    }\n}","preventionTips":["Make audit logs append-only at the OS level where feasible.","Never edit, redact, or reformat audit lines in place; derive views instead.","Include hash-chain verification in log-shipping pipelines (verify before ship, verify after land)."],"tags":["audit","integrity","hash-chain","tamper-detection","verification"],"backgroundTag":"hash-chain-mismatch","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}