Skip to content

All lessons

Area 06 // AI SecurityLesson 103 / 14013 min read

Audit logging

An audit log is a tamper-resistant record of who did what, when, on whose behalf and with what result, including every tool call, approval and data access an AI agent makes, kept so you can investigate incidents, prove compliance and spot abuse.

Think of it like this

Analogy

A bank vault's visitor book: every entry records who came in, who they were with, which box they opened, who authorised it and when they left. Pages are numbered and bound, so you can't quietly tear one out. Nobody reads it daily, but after a theft it's the first thing investigators open.

The problem it solves

An agent refunded £40,000 overnight. Which user asked? Which tool calls ran, with what arguments? Was it approved, and by whom? Which prompt and model version made the decision? Did someone edit the record afterwards? Without a proper audit trail, you can't answer, can't prove compliance to regulators or customers, and can't tell an attack from a bug.

How it works, step by step

  1. Decide what's auditable: logins and permission changes, data access (especially sensitive documents), every agent tool call, approvals and denials, configuration and prompt changes, model or provider changes, admin actions and data exports.
  2. Record a structured event for each:
    • Who: user ID, agent ID, and on behalf of whom (agent authorization).
    • What: action, tool, arguments (redacted), resource IDs, data sources read.
    • When and where: timestamp, service, region.
    • Result: success, failure, denied, and why.
    • Context: trace ID linking to the full trace (tracing), approver, model and prompt version (versioning).
  3. Redact: identifiers and references, not raw PII, secrets or full documents (PII).
  4. Make it tamper-resistant: append-only, write-once storage (object lock, WORM), a separate account or service that the app can write to but not delete from, and hash chains or signatures to detect edits (see the code).
  5. Control access: few people can read it, every read is itself logged.
  6. Retain for the period your policies and regulations require, then delete.
  7. Use it: alerts on suspicious patterns (many denials, unusual tools, large exports), regular reviews, and incident investigations.
Every security-relevant action writes an event to a store the app can append to but never edit.

See it in code

Needs
Nothing: plain Python 3.

A hash-chained audit log: three agent events, a verification, then a quiet edit that verification catches.

audit_log.py
import hashlib, json
 
# An append-only audit log where each entry includes the hash of the previous one (a hash chain),
# so editing or deleting an old entry is detectable.
log = []
def audit(actor: str, action: str, **details):
    prev = log[-1]["hash"] if log else "genesis"
    entry = {"seq": len(log) + 1, "actor": actor, "action": action, "details": details, "prev": prev}
    entry["hash"] = hashlib.sha256(json.dumps(entry, sort_keys=True).encode()).hexdigest()[:16]
    log.append(entry)
 
def verify(entries) -> str:
    prev = "genesis"
    for e in entries:
        body = {k: v for k, v in e.items() if k != "hash"}
        if e["prev"] != prev or hashlib.sha256(json.dumps(body, sort_keys=True).encode()).hexdigest()[:16] != e["hash"]:
            return f"TAMPERED at entry {e['seq']}"
        prev = e["hash"]
    return "intact"
 
audit("agent:support-bot (for user:alice)", "tool_call", tool="get_order", order="ORD-10001", trace="t-81f2")
audit("agent:support-bot (for user:alice)", "tool_call", tool="refund", amount=450, trace="t-81f2")
audit("user:manager-dev", "approval", approved="refund 450", trace="t-81f2")
for e in log:
    print(e["seq"], e["actor"], e["action"], e["details"], e["hash"])
print("check:", verify(log))
log[1]["details"]["amount"] = 45                  # someone quietly edits history...
print("check:", verify(log))
Output
1 agent:support-bot (for user:alice) tool_call {'tool': 'get_order', 'order': 'ORD-10001', 'trace': 't-81f2'} 19bd0754d362357f
2 agent:support-bot (for user:alice) tool_call {'tool': 'refund', 'amount': 450, 'trace': 't-81f2'} a5c38b94ef8f5637
3 user:manager-dev approval {'approved': 'refund 450', 'trace': 't-81f2'} 0688fe3387bf1091
check: intact
check: TAMPERED at entry 2

The shared trace ID ties the refund to its approval and to the full trace. In production you'd also store periodic chain heads somewhere separate (or use write-once storage), since an attacker who can rewrite the whole chain could recompute every hash.

A real example

Example

Answering the regulator in an afternoon

A lender used an AI assistant to help staff draft decisions on hardship requests. A customer complained that their request had been rejected by "a robot". Because every assistant session logged the staff member, the documents retrieved, the model and prompt version, the draft produced, and the human who made the final decision, the compliance team reconstructed the case in an afternoon: the assistant had recommended approval and a human had overridden it with a documented reason. The audit trail, stored in write-once storage for seven years, answered the regulator's questions directly.

The easy way

Start here

Write one structured JSON event per tool call, approval and permission change (who, on behalf of, what, result, trace ID) to a separate log stream that your app can append to but not delete, and keep it longer than your normal logs.

When you grow: the production setup

Teams define an audit event schema shared across services, ship events to a dedicated store with object lock or WORM retention in a separate account, hash-chain or sign batches, restrict and log access, redact at the source, correlate with traces, feed security monitoring (SIEM) with alert rules for agent anomalies, and test that critical actions always produce events.

Trade-offs

What you gain

  • Incidents can be investigated and explained.
  • Supports compliance and customer trust.
  • Detects abuse and misbehaving agents.

What it costs you

  • Storage and tooling costs, especially with long retention.
  • Logs themselves become sensitive data.
  • Needs discipline to keep the event schema complete.

When not to use it

  • Don't skip it for anything with tools or sensitive data; a toy app may only need normal logs.

Common mistakes

  • Relying on debug logs that are sampled, unstructured and deleted after a week.
  • Logging raw prompts full of PII into long-lived audit stores.
  • Not recording on whose behalf the agent acted.
  • Letting the application delete or overwrite its own audit entries.
  • Collecting audit logs nobody ever alerts on or reviews.

Interview questions

Try answering out loud first, then open the model answer.

What would you include in an audit log for an AI agent?

Model answer

Structured events for every tool call (tool, redacted arguments, resource IDs, result), denials and approvals (with approver), data sources accessed, the user the agent acted for, agent ID, model and prompt versions, timestamps, and a trace ID linking to full traces, plus configuration and permission changes.

How do you make audit logs trustworthy?

Model answer

Write to append-only, write-once storage in a separate account where the application can't delete; hash-chain or sign entries and store chain heads separately; restrict and log read access; synchronise clocks; redact sensitive content; and test regularly that events are complete and verifiable.

How are audit logs different from traces in LLM observability?

Model answer

Traces capture detailed execution for debugging and quality (inputs, outputs, timings), are often sampled and short-lived, and are read by engineers. Audit logs capture who did what for accountability and security, must be complete for covered events, tamper-resistant, redacted and retained long-term. They share trace IDs so you can move from one to the other.

Quiz

Pick an answer to see whether it’s right and why.

  1. 01What's the key difference between audit logs and debug logs?
  2. 02For an AI agent, what must be in the audit log?
  3. 03How does a hash chain make tampering detectable?
  4. 04Why should audit logs be redacted?
  5. 05Who should be able to delete audit log entries?

0 of 5 answered

Key terms

Audit log
A complete, tamper-resistant record of security-relevant actions (who did what, on whose behalf, when and with what result), kept for investigations and compliance.
Trace
The full record of one request or task, made of nested timed spans for every step it took.
Append-only
Storage where new records can be added but existing ones can't be changed or deleted, which keeps audit trails trustworthy.
Hash chain
A sequence of records where each includes the hash of the previous one, so changing any record breaks every later link and is easy to detect.
Retention period
How long data such as logs or conversations is kept before it is deleted, set by policy and law.

Before and after

Progress is saved in this browser only.