Insights
AI agent audit trails: record the decision and the effect, not everything
A useful audit trail does not answer only “what did the model say?”. It answers who requested the action, what the system authorised, which tool was used, what happened in the target system and what state remained after the operation.
That distinction matters. A full prompt and response can help debugging, but they do not replace an operational record. They can also contain data that should never be copied into a logging system.
Start with the incident-reconstruction question
Suppose an agent changed a campaign budget or a user's permission two weeks ago. Today somebody asks:
- who initiated the change;
- whether the operator was authorised to request it;
- how the operation was classified;
- whether human approval was required;
- who approved exactly what;
- which relevant parameters were passed to the tool;
- what the external provider returned;
- whether resulting state was verified;
- which version of the security policy applied.
If answering those questions requires manually combining chat history, HTTP logs, a database and the provider console, we have logs. We do not yet have a good audit trail.
A minimum operation record for an agent
Every system will differ. For tool-using agents, a useful core is:
| Field | Why record it |
|---|---|
event_id |
uniquely identify the event |
timestamp |
order and timing |
operator_id |
person or principal requesting the action |
agent_id / agent_version |
identify the agent/model involved |
task_id / correlation_id |
connect multiple calls into one workflow |
tool |
tool or method used |
operation_class |
read / write / operate / destructive or local equivalent |
target_resource |
account, tenant, project or resource affected |
authorization_decision |
allow / deny plus scopes/policy used |
approval_id |
evidence of approval when required |
request_fingerprint |
fingerprint of normalised parameters when full data is unnecessary |
provider_result |
controlled outcome without secrets |
resulting_state |
state read after the change, or evidence reference |
policy_version |
ruleset that applied at execution time |
Not every value needs to be stored as text in the same record. Some can reference separate evidence artefacts. The important thing is being able to reconstruct the chain coherently.
Conversation logs and audit trails solve different problems
A conversation log provides context
It can show what the user asked, what the model answered and which information was present in the session.
An audit trail provides execution evidence
It should show:
operator
→ authorization decision
→ tool
→ parameters material to the action
→ approval if required
→ provider outcome
→ resulting state
If a model writes “the campaign has been paused” but there is no tool event and no state read from the target system, we have a claim. We do not have execution evidence.
What usually belongs on the redaction or exclusion list
More logging does not automatically mean better auditability. It can mean a larger data-leak surface.
In our internal Brillnet Ads MCP, credentials, authorization headers and raw personal identifiers are excluded from audit records. The same direction is useful elsewhere.
Do not log secrets
- API keys;
- access or refresh tokens;
- private keys;
- passwords;
- session cookies;
- complete
Authorizationheaders.
If an audit record needs to show which identity or credential set was used, store a safe reference identifier rather than the secret itself.
Do not copy every request and response automatically
A raw API response can contain personal data, confidential fields or information that is irrelevant to the audit purpose. Select the metadata needed for the decision and the resulting state instead.
Do not make full prompts a mandatory part of the audit record
Prompts can be useful for diagnostics. They can also contain customer documents, personal data or a secret pasted by mistake. Prompt retention should follow a separate data-retention and access policy, not the assumption that “AI means log everything”.
Redact before persistence
If we persist a complete payload first and run masking later, the secret has already entered the logging system.
A safer flow is:
tool returns outcome
↓
normalisation
↓
field classification
↓
redaction / pseudonymisation
↓
audit record persistence
Sensitive data can remain in the source system that already has its own access and retention controls. The audit system should retain the minimum needed to reconstruct the decision and effect.
Read-after-write closes the gap between “called” and “changed”
For write operations, we record not only the call outcome but — when the provider allows it — the target resource state read after the change.
Example:
14:02:11 write request: campaign status → PAUSED
14:02:12 provider: success
14:02:13 read-after-write: campaign.status = PAUSED
That lets us distinguish:
- the agent requested a change;
- the provider accepted the request;
- the resource had the expected state when it was verified.
This does not prove the state never changed a second later. It is still much stronger evidence than a model message saying “done”.
Approval should be an independent audit event
Human approval should have its own identifier and bind to a specific operation.
A conceptual record might include:
approval_id: apr_...
approved_by: operator_...
approved_at: 2026-09-12T14:01:44+02:00
action_hash: sha256(...)
operation: ENABLE_CAMPAIGN
target: campaign_...
expires_at: ...
The executor can then verify that approval exists for this exact version of the operation instead of trusting a chat message saying “the user agreed”.
Read: When should an AI agent require human approval?
Integrity: append-only records and hash chaining
In our internal Ads MCP tool, audit records are append-only and hash-chained. The aim is to make silent alteration of history easier to detect.
Conceptually:
record_1 + hash(record_1)
↓
record_2 contains hash(record_1)
↓
record_3 contains hash(record_2)
If an older record changes, subsequent links no longer match.
This is not magical immutability. An administrator with sufficiently broad access can still destroy the logging system or the entire store. Record integrity should therefore be combined with:
- restricted log access;
- defined retention;
- backup/export where justified;
- monitoring for gaps or chain failures;
- controlled time and identifiers.
Useful telemetry for MCP tools
For tools/call or an equivalent local operation, useful fields often include:
- tool name;
- risk category;
- normalised resource identifiers;
- scopes evaluated;
- authorization outcome;
- whether an action preview was shown;
- approval identifier;
- start and end time;
- provider status;
- controlled error code;
- whether a retry occurred;
- idempotency key or a safe fingerprint of it;
- resulting state after a write;
- model/agent identifier to the extent needed for diagnostics.
That does not require storing every raw tool argument.
What about chain-of-thought?
We do not need a model's private chain of thought to create a useful operational audit trail. We need observable facts:
- decision-relevant input;
- selected operation;
- policy applied;
- approval;
- outcome;
- resulting state.
When a rationale is useful, an agent can write a short explicit decision_reason designed for review. That is different from trying to preserve a model's hidden reasoning process.
Retention: “forever” is usually a poor default
For each event class, define:
- processing purpose;
- retention period;
- who can access it;
- whether data can be aggregated or pseudonymised;
- when a record is business evidence versus engineering telemetry;
- how lawful/operational deletion works where required.
Do not keep debugging telemetry and formal decision records together indefinitely without a reason.
Example incident reconstruction
Situation: a campaign started generating spend even though it was expected to remain paused.
A useful audit trail should let us follow:
task_id— where the request came from;operator_id— who initiated it;tool— which tool was selected;operation_class=operate— why additional control applied;approval_id— whether somebody actually approved activation;- parameters — which status and budget were covered by approval;
- provider result — what Google Ads accepted;
- read-after-write — what state was observed after execution;
- later events — whether another actor changed the status again.
Without that chain, we are left reading chat history and guessing.
AI-agent audit trail checklist
- Every material event has a unique ID and timestamp.
- Operator identity and agent identity are distinct.
- Multiple calls can be joined by one task/correlation ID.
- Authorization decisions are recorded, not only successful calls.
- Approval is a separate verifiable event.
- Parameters material to the consequence are stored or fingerprinted.
- Secrets and authorization headers are excluded before persistence.
- Personal data is minimised/redacted.
- Retries and idempotency are observable.
- Writes have provider outcome and, where practical, read-after-write evidence.
- Policy version can be reconstructed.
- Audit access is more restricted than ordinary application access.
- Retention is defined rather than accidental.
- Integrity of the trail is monitored.
Sources
Boundary
An audit trail does not automatically prove that a decision was correct. It proves what the system recorded about how the action was authorised and executed. Regulated processes may need additional requirements for integrity, retention, privacy and evidentiary quality.
See also Least privilege for AI agents and Brillnet Security.
