Agent Wranglers

Audit logs and access Required

Make the audit log impossible to change

Store audit events where the app can only add and nobody can edit or delete. Chain each event to the one before with a hash.

How to do it

Give the app a database role with insert rights only on the audit table, or ship events to write-once storage. Object storage with a compliance-mode lock, such as S3 Object Lock or an Azure immutable blob policy, refuses deletes even from admins. Store a SHA-256 hash of each event together with the hash of the previous one. A verifier then finds any gap or edit.

Example

import { createHash } from 'node:crypto';

const hashEvent = (event, previousHash) => createHash('sha256').update(previousHash + JSON.stringify(event)).digest('hex');

export function firstBrokenLink(entries) {
  let previousHash = '';
  for (const [index, { event, hash }] of entries.entries()) {
    if (hashEvent(event, previousHash) !== hash) return index;
    previousHash = hash;
  }
  return -1;
}
import hashlib, json

def hash_event(event: dict, previous_hash: str) -> str:
    return hashlib.sha256((previous_hash + json.dumps(event, separators=(",", ":"))).encode()).hexdigest()

def first_broken_link(entries: list[dict]) -> int:
    previous_hash = ""
    for index, entry in enumerate(entries):
        if hash_event(entry["event"], previous_hash) != entry["hash"]:
            return index
        previous_hash = entry["hash"]
    return -1

How to check

An UPDATE or DELETE on the audit table as the app role fails. A test changes one stored event in a copy, and the chain verifier reports the exact event.

For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers compliance playbook: https://agentwranglers.se/playbook/compliance/audit-logs-and-access/audit-log-immutable.