The Audit Side-Channel: Recording Agent Actions Where The Agent Cannot Edit The Recording
An agent that writes its own audit log is an agent whose audit log is fiction. The side-channel is the architectural choice that turns logs into evidence.
Continue the reading path
Topic hub
Runtime GovernanceThis page is routed through Armalo's metadata-defined runtime governance hub rather than a loose category bucket.
Turn this trust model into a scored agent.
Start with a 14-day Pro trial, register a starter agent, and get a measurable score before you wire a production endpoint.
TL;DR
An agent that controls its own audit log controls the story that gets told about it. That is the architectural fact, and it has consequences. Self-logging agents will, under compromise, edit their logs to hide compromise. Self-logging agents will, under bug, write inconsistent logs that obscure root cause. Self-logging agents will, under operator pressure, omit details that would be embarrassing. The audit side-channel is the only structural fix: a separate logging service the agent has no write authority over, append-only at the storage layer, signed by an operator key that the agent cannot reach. This piece walks through the architecture, the threat model it defends against, the specific cryptographic and process properties that make it work, and a reference architecture that converts agent actions into evidence rather than narrative.
The Failure Mode That Forces The Side-Channel
A financial reconciliation agent runs in production for months, processing inter-account transfers and reconciling them against a ledger system. It has an internal audit log that records every transfer it initiates, with the timestamps, amounts, source and destination accounts, and a brief reasoning string. The team treats this log as the source of truth for the agent's behavior. It is queryable, structured, and consistent. They use it for monthly compliance reports, quarterly audits, and the occasional individual transfer investigation when someone has a question.
One Friday afternoon, a customer reports that an unexpected transfer occurred on their account three weeks earlier. The team queries the agent's audit log for the relevant time window. The log shows the agent processing several transfers in that window, but nothing matching the customer's report. The team initially concludes that the customer is mistaken, perhaps misreading their statement. The customer escalates. The team pulls bank-side records, which confirm that the transfer did occur and that it originated from the agent's account credentials. There is now a transfer in the world that the agent's audit log does not show.
The team begins a deeper investigation. They check the agent's process logs, which corroborate the audit log: nothing about the disputed transfer. They check the database state, which is consistent with the audit log: no record of the transfer. They check the agent's memory store, which contains traces of customer interactions in the relevant window, and they find a chain of messages that suggests the agent did process the transfer, but with the audit-writing step skipped. They eventually trace the cause to a runtime error during one specific code path: when a particular type of API response was received from the bank, the agent's exception handler had a bug that aborted the audit-write before it completed, but did not roll back the actual transfer.
The bug is fixed within a day. The deeper problem takes longer to acknowledge. The audit log was a record of what the agent's code believed it had done, not a record of what the agent actually did. The two had diverged in this case because of a bug; they could equally diverge because of compromise (an attacker who suppressed the audit-write before exfiltrating funds), or because of an operator's deliberate intervention (a debug-flag toggle that disabled audit during a maintenance window), or because of a schema migration error (a column rename that quietly stopped certain fields from being persisted). In every case, the agent's self-audit is the wrong thing to ask, because the question "did this agent do this thing" cannot be answered by querying the same system that did or did not do the thing.
The team's response is to build a separate logging service that lives outside the agent's process and that receives every action the agent intends to take, before the action is executed. The agent does not have write authority over this service. The agent emits an event over a one-way channel, and the service writes the event to its own append-only store. The agent's process logs continue to exist for debugging, but the audit-of-record now lives where the agent cannot reach it. The team backfills two months of historical actions from bank records and database state, and resolves to never again let the audit-writer be the same code path as the audited action.
What "Side-Channel" Actually Means
A side-channel, in this context, is a logging path that is structurally separate from the action path it records. The agent performs some action: a tool call, a transaction, a memory write, a network request. Before, during, or after the action, the agent emits an event describing the action over a one-way channel to a logging service. The logging service writes the event to its own store, which is append-only at the storage layer. The agent has no read or write authority over this store; the agent can only emit events, and the emission is observed by infrastructure the agent does not control.
The separation has several axes. The first is process separation: the logging service runs as a different process, often on different infrastructure, with its own identity and its own resources. The agent cannot crash the logging service by failing in interesting ways, and the logging service cannot be compromised by the same vulnerabilities that compromise the agent. The second is authority separation: the agent's credentials grant it no rights to read, modify, or delete entries in the logging store; the only authority the agent has is to emit. The third is process-of-record separation: the logging store is the canonical record of what happened, and the agent's own internal logs are a separate, lower-trust record useful only for debugging.
The channel between the agent and the logging service is one-way and lossy in a controlled way. One-way means the agent cannot observe what the logging service does with its emissions; it can only emit. Lossy in a controlled way means the channel has well-defined semantics for what happens when emission fails: the agent's action is either gated on successful emission (write-then-act, with the action blocked until the emission is acknowledged), or proceeds optimistically with a separate background reconciliation that detects emissions that were attempted but never landed. Most production systems use a hybrid: high-stakes actions block on emission, low-stakes actions proceed optimistically with reconciliation.
The critical property is that no compromise of the agent grants the attacker authority over the audit log. An attacker who fully owns the agent process can stop the agent from emitting future events; they cannot retroactively modify or delete events that have already been emitted, because those events live in a store the attacker has no path to. The audit log therefore captures everything the agent did before compromise, plus a clean cutoff at the moment compromise began (signaled by a sudden absence of emissions from a previously-emitting agent). The cutoff is itself a signal, and detection logic that monitors emission patterns can flag an agent that has gone quiet as a likely compromise candidate.
Append-Only Is The Whole Game
The storage layer of the side-channel must be append-only. Append-only means: once an entry is written, it cannot be modified or deleted by any normal operation. New entries can be added; existing entries are immutable. This property is the foundation of every other guarantee the system provides. A log that supports modification supports rewriting history. A log that supports deletion supports removing inconvenient evidence. A log that does neither supports neither.
Append-only is a discipline at multiple layers. At the application layer, the logging service exposes only an emit endpoint; no edit, no delete, no overwrite. The endpoint accepts a structured event, validates it against a schema, attaches a server-side timestamp from a trusted clock source, computes a hash chained to the previous entry, and writes the resulting record to durable storage. The chaining means each entry contains a hash of the previous entry, so any modification to historical entries invalidates the chain from the modification point forward, which is detectable by any reader.
At the storage layer, the underlying store should not support in-place modification. Object storage with object lock (S3 with compliance-mode versioning, equivalent capabilities on other clouds) is one option; specialized append-only databases (like QLDB or specialized event stores) are another; replicated, signed log services that are themselves backed by hardware-protected storage are a third. The exact choice depends on operational constraints, but the property is the same: no path exists, even for a privileged operator, to silently overwrite historical entries.
At the operational layer, the keys that sign the entries must not also have authority to delete or modify entries in the store. This separation prevents an operator with key access from using that access to rewrite history. The signing key is held by the logging service and is used only to sign new entries; the storage authority is held by an infrastructure team and is used only to provision and retire storage volumes. The two roles are separated by policy and audited independently.
The practical implication is that, even under operator compromise, the audit log retains its evidentiary value for any entries written before the compromise. An attacker who steals the operator credentials can stop emitting future entries (by disrupting the logging service), can sign forged entries and add them as new entries (which then become part of the historical chain and are detectable as suspicious by their content), but cannot retroactively modify or delete entries that already exist. The historical record is preserved against compromise, which is the property that distinguishes audit from logging.
Cryptographic Tamper-Evidence
Append-only is necessary but not sufficient. The storage layer might be append-only by configuration, but configurations change. The signing key might be properly separated by policy, but policies get bypassed during incidents. The reader of the audit log needs a way to verify, independently, that the log they are reading has not been tampered with, regardless of what the operator's storage configuration claims to be.
The verification mechanism is hash chaining plus periodic anchoring. Each entry in the log contains a hash of the entry plus a hash of the previous entry. The chain of hashes forms a Merkle-style structure where any modification to any historical entry invalidates the hash chain from that point forward. A reader who computes the chain forward from a known-good point and compares against the stored hashes will detect any tampering, because the chain will fail to verify at the modified entry.
The periodic anchoring solves the bootstrap problem of "known-good point." At regular intervals (say, every hour), the logging service publishes the current chain head to an external public log: a transparency log, a public blockchain, or a third-party time-stamping service. The publication is a public commitment that the log contained certain entries up to a certain point, signed by the logging service and witnessed by an external party. Any subsequent verification can pin its known-good point to one of these public anchors, which means the operator cannot rewrite history without rewriting the public anchors as well, which they cannot.
The anchoring frequency is a tradeoff. More frequent anchors means smaller windows during which silent tampering is possible; less frequent anchors means lower operational cost and less external dependency. Most production deployments use anchoring on the order of every five to fifteen minutes, with the anchors published to multiple destinations to avoid single-point-of-failure on the witness. The cost is small (a few transactions per hour to a public log) and the benefit is the property that any tampering older than the most recent anchor is detectable by any reader.
The entry signatures themselves use a key that lives in the logging service and that is rotated regularly through a separate identity infrastructure. Signing key rotation does not break historical verification because each entry is signed at write time with whatever key was current then, and the verification logic walks the rotation history to confirm that each historical signature was valid against the key in force at the corresponding time. The key rotation history is itself logged in a public, append-only place (the same anchoring infrastructure), so the chain of signing keys is auditable end to end.
What An Audit Entry Should Actually Contain
An audit entry is not a debug log. It is a structured statement about what happened, oriented toward the questions that auditors and forensic investigators will eventually ask. The schema should be rich enough to answer those questions without requiring access to the agent's internal state, because the agent's internal state at the time of the event will not exist by the time the question is asked.
The minimum useful schema includes: a unique entry identifier, a timestamp from a trusted clock source, the agent identifier with pact reference and pact version, the action category (transaction, memory_write, tool_call, network_request, etc.), the specific action subtype, the action parameters (with PII fields hashed or redacted as policy requires), the action target (account, URL, tool, memory entry, etc.), the action outcome (success, failure, denied, partial), the resource cost (CPU, tokens, dollars), the relevant context references (request identifier, session identifier, decision identifier), the previous entry hash, the entry signature, and the witness anchor reference if applicable.
The parameters field needs careful handling. Some parameters are sensitive (credentials, customer PII, financial details) and should not be stored in plaintext in the audit log. The standard treatment is to store hashed or redacted forms, with the unredacted values held in a separate access-controlled store that the auditor can request through a documented disclosure process. The audit entry contains enough information to identify what was passed without revealing the contents, and the disclosure process provides the contents to authorized parties under controlled conditions.
The context references are what make audit entries traceable across systems. A transaction audit entry references the originating decision, which references the relevant attestation manifest, which references the memory entries that informed the decision, which references the conversation turn that produced the decision. The chain of references means that any single audit entry can be expanded into a full forensic story by walking the references, which is exactly what investigators need when they have a single observation and need to reconstruct the surrounding circumstances.
The outcome field is critical and underappreciated. Many audit logs record only successful actions, on the theory that failures are not interesting. This is wrong. Failures are often more interesting than successes, because they reveal what the agent attempted to do that was blocked. A denied transaction is evidence that the agent tried to do something its policy did not permit, which is exactly the kind of behavioral signal that matters for compromise detection. The audit log must capture every attempt, with the outcome distinguishing what happened to it, and the analysis tooling on top of the log must surface failures and denials with the same prominence as successes.
Reader Artifact: The Audit Side-Channel Architecture
The specification below defines the reference architecture for an Armalo audit side-channel. It captures the components, the data flow, and the key separations that make the architecture defensible.
[Agent Process]
|
| emit(event) -- one-way, authenticated as agent identity
v
[Audit Submitter Sidecar]
|
| gRPC, mTLS to audit endpoint, agent has no further access
v
[Audit Service Cluster]
|
| - Validates schema
| - Adds server-side timestamp from trusted clock
| - Computes chain hash from previous entry
| - Signs entry with audit service key (HSM-backed)
| - Writes to append-only store
| - Acks to submitter (for blocking emits)
v
[Append-Only Storage]
|
| - Object storage with compliance-mode lock
| - Or specialized event store with cryptographic chaining
| - Storage authority held by separate ops team, not agent operators
v
[Periodic Anchoring]
|
| Every N minutes:
| - Compute current chain head hash
| - Publish to external transparency log
| - Publish to optional second witness (public chain, third-party TSA)
v
[Verification API]
|
| - Read-only, public for auditors
| - Returns entries with chain hashes
| - Returns rotation history of signing keys
| - Returns anchor history with witness references
| - Anyone can independently verify chain integrity end-to-end
Key separations:
- Agent has emit-only authority, no read, no modify, no delete
- Audit service has sign-only authority on entries, no storage modify
- Storage authority held by separate team, audited independently
- Anchor witness is external, not under operator control
Key properties:
- Append-only at storage layer (compliance lock or equivalent)
- Hash chaining at application layer (tamper-evident)
- Periodic anchoring at audit layer (operator cannot rewrite history)
- Signature verification end-to-end against published key history
The reference architecture is deliberately conservative. Production deployments may simplify some elements (a single witness instead of two, a smaller anchoring frequency, a colocated audit service for low-stakes use cases), but each simplification weakens specific guarantees, and the simplifications should be made with explicit awareness of which guarantees are being traded. The architecture above represents the strong default, suitable for any agent handling regulated, financial, or high-trust workloads.
Counter-Argument: This Is What Logging Vendors Already Do
The counter-argument is that every logging vendor on the market sells append-only audit logging as a standard feature. Splunk, Datadog, AWS CloudTrail, GCP Audit Logs, and a long tail of compliance-focused vendors all offer immutable storage, retention policies, and cryptographic verification. Building a separate side-channel architecture is reinventing what the vendors have already built.
This is partially correct and substantively wrong. Vendors do offer immutable storage, but the immutability typically depends on the customer's configuration, which the customer can change, which the customer's compromise scenarios can change. The vendor's commitment is usually "we will not modify your data," not "your data cannot be modified." The distinction is subtle but it matters for the threat model: vendor-side immutability protects against vendor compromise, customer-side immutability protects against customer compromise. The audit side-channel as described in this piece is about customer-side immutability, because the threat model includes the customer's own operational mistakes and compromise events.
The second part of the counter-argument is that the agent context is not special, that any sufficiently sensitive system already has audit logging discipline, and that calling it a side-channel for agents is just rebranding existing practice. This is partially true. The discipline is the same. What is different is the application: agent operators, who often come from ML or product backgrounds, frequently treat audit logs as developer convenience rather than as a security boundary, and the same logs that would be appropriately separated and protected in a financial services context are deployed casually in agent workloads. The piece is partly a statement of established practice and partly a statement of which established practice agent operators must adopt.
The third part of the counter-argument is the operational cost. A separate audit service is a separate system to deploy, monitor, scale, and incident-respond on. Many small teams will resist the additional surface area. The response is the same as for provenance: this is platform-level infrastructure, paid for once by the runtime vendor or platform team, inherited by every agent that runs on the platform. It is not a per-agent cost. The threshold for adoption is the platform team committing to it once, after which the cost amortizes across every agent deployed on the platform.
The Read Path Matters As Much As The Write Path
Most discussions of audit logging focus on the write path: how to capture events, how to sign them, how to store them durably. The read path gets less attention and is, in practice, where many audit systems fail to deliver value. A perfectly written audit log that nobody can query effectively is an audit log that does not exist for operational purposes. The read path is the part that converts the captured evidence into actionable knowledge, and it deserves the same architectural rigor as the write path.
The read path has several distinct usage patterns, each with its own requirements. Routine operational queries: "what did this agent do today," "how many transactions over $1,000 happened this week," "which agents touched customer X's account." These queries are frequent and should be fast. Forensic deep-dives: "reconstruct everything that happened around the disputed transfer at 13:47:22 on March 14." These queries are rare but require comprehensive context, including all related entries linked through cross-references. Compliance reports: "summarize all actions in the past quarter for category Y." These queries operate on large time windows and benefit from pre-computed aggregations. External auditor access: "verify the integrity of the chain between dates A and B." These queries are infrequent but have to be served to parties who do not have inside knowledge of the system.
The storage architecture has to support all of these patterns without compromising the append-only property. The typical solution is a tiered approach: a hot tier holds recent entries in a searchable index optimized for query patterns one and two; a cold tier holds historical entries in compact storage optimized for pattern three; both tiers expose the chain hashes and signatures needed to support pattern four. The hot tier is rebuilt as needed; the cold tier is the canonical store, and any rebuild of the hot tier verifies against the cold tier's hashes.
Query interfaces should be structured around the questions investigators actually ask, not around the schema of the stored events. An investigator does not want to write SQL against an event table; they want to ask "show me everything related to transaction T," and the query interface should walk the cross-references automatically and present a unified view. This is the equivalent of a CRM 360-degree view applied to audit events: a single starting identifier expands into all the related events across the agent's history, the audit chain, the attestation manifests, and the linked external systems.
The read path also needs to handle the case of contested entries. If a counterparty challenges the integrity of a specific entry, the read interface should be able to produce, on demand, the entry plus its position in the hash chain, the signing key in force at the time, the certificate chain of that key, the relevant transparency log entries, and the witness anchors that bookend the entry. This is the evidence packet that converts "trust me" into "here is the cryptographic proof." Building the read interface to produce these packets quickly and reliably is what makes the audit system useful in disputes; without it, every dispute becomes a multi-day forensic project.
Cross-Service Correlation Is What Makes The Log Investigable
A single agent's audit log captures what that agent did. A single transaction usually involves multiple agents, multiple services, and external systems. Investigating an incident often requires correlating events across all of these sources, and the correlation only works if the audit entries carry shared identifiers that can be joined across logs.
The standard mechanism is the request identifier, a unique value assigned at the entry point of an interaction and propagated to every downstream service that participates. The agent emits audit entries tagged with this identifier; the upstream service emits entries tagged with the same identifier; the database emits query entries tagged with the same identifier; the external API records the call with the same identifier in the response headers. When an investigator wants to reconstruct an interaction, they query each log by the identifier and reassemble the timeline.
Several additional identifiers serve different correlation purposes. The session identifier groups related interactions over a period of user engagement. The decision identifier links the agent's commitment to a specific outcome. The transaction identifier joins financial events across the ledger and the agent's view. The pact reference ties all of an agent's actions back to its declared scope. Each identifier is established at the appropriate level of granularity and propagated consistently across all services that participate.
The propagation discipline is part of the runtime contract. Services that do not propagate identifiers correctly are services whose audit entries cannot be correlated, which means investigations that touch those services will have gaps. The runtime should enforce propagation at the boundaries: every outbound call from an agent carries the relevant identifiers in headers, every inbound call validates that the identifiers are present and well-formed. The discipline is small per-call cost (a few headers) and large investigative payoff.
The correlation also supports automated detection. Pattern queries that span multiple agents can identify coordinated misbehavior: agent A consistently triggers a particular response from agent B that produces an unexpected outcome in service C. These patterns are invisible in any single log but obvious when the logs are correlated. Building correlation tooling is therefore not just an investigative aid; it is a detection capability that catches multi-agent issues that would otherwise go unnoticed.
The end state is an investigative experience where the operator types in any identifier (request, session, decision, transaction, pact reference) and gets back a complete cross-service timeline of every event linked to that identifier, presented in a way that tells the story of the interaction. This is the level of read-path capability that makes audit logs operationally useful, and it is achievable with the same architectural primitives (chained, signed, append-only entries with rich identifier structure) that make the write path defensible.
What Armalo Does
The Armalo runtime emits every consequential agent action to a separate audit service over a one-way authenticated channel. The agent has emit-only authority; it cannot read, modify, or delete entries in the audit store. The audit service validates the event against a schema, attaches a trusted timestamp, computes a chain hash from the previous entry, signs the entry with an HSM-backed key, and writes to compliance-mode object storage that is administered by a separate operations team. Every fifteen minutes, the audit service publishes the current chain head to an external transparency log, providing public anchors that the operator cannot rewrite. The verification API is read-only and publicly accessible, allowing any auditor to walk the chain end-to-end and confirm that the log has not been tampered with. Pacts can require minimum audit retention and anchoring frequencies, with non-compliance feeding back into the agent's pact compliance dimension on the composite score.
FAQ
Q: What happens if the audit service is unavailable when the agent wants to emit? A: For high-stakes actions, the agent blocks until emission succeeds, with the action gated on emission acknowledgment. For lower-stakes actions, the agent emits optimistically and a separate reconciliation process detects gaps. The choice between blocking and optimistic is a per-action-category decision in the agent's pact, with stakes-versus-availability tradeoffs explicit and reviewable.
Q: Can the agent buffer events locally if the audit service is unreachable? A: Yes, but with strict bounds. Local buffers are temporary holding areas that flush to the audit service when connectivity returns. The buffer is bounded in size and time; events that cannot be flushed within the bound are escalated, and the agent's behavior is curtailed (high-stakes actions are blocked) until the buffer drains. The local buffer is not a replacement for the audit service; it is a continuity bridge for transient outages.
Q: How do you handle PII in audit entries? A: PII fields are redacted or hashed at emission time, with the unredacted values held in a separate access-controlled store keyed by the audit entry identifier. The audit log contains enough structure to answer most operational questions without unredacted access. Disclosure of unredacted values is a documented process requiring authorization, and every disclosure is itself audited.
Q: What happens during agent state migrations or platform changes? A: The audit chain spans the migration. Entries written before and after the migration are linked in the same chain, with a special migration entry that records the change and references the relevant configuration. Migration discontinuities are themselves auditable events, and the chain integrity is preserved through them.
Q: Can multiple agents share an audit chain? A: Each agent has its own chain to keep emission rates manageable and to scope verification. Cross-agent investigations walk multiple chains, joined by shared identifiers like decision identifiers or transaction identifiers. A single shared chain across all agents would be operationally untenable at scale.
Q: How long are audit logs retained? A: At least as long as the legal exposure window for the agent's actions, typically seven years for financial workloads and shorter for low-stakes use cases. Retention is policy-driven, with the retention policy itself audited. Deletion at the end of the retention window is logged as a final entry and is part of the chain, so the deletion itself is verifiable.
Q: Can an attacker poison the audit log by emitting false events? A: The attacker can only emit events the agent's identity authorizes, and emitted events carry the agent's identity. False events therefore appear as the agent claiming to have done things, which is detectable by cross-referencing against external sources of truth (database state, partner system records, etc.). Poisoning the log is a different attack from forging the log, and it is detectable through normal investigation rather than through chain verification.
Q: What about latency? The blocking-emit path adds round-trips to high-stakes actions. A: Yes, typically tens of milliseconds for the round trip to a regional audit service. For high-stakes actions, this latency is acceptable because the actions themselves are not latency-sensitive at that scale. For low-stakes actions where latency matters, optimistic emission with reconciliation provides comparable evidentiary value with no blocking cost.
Bottom Line
An agent that controls its own audit log controls the story of its own behavior, which means the audit log is no longer evidence. It is narrative. The fix is structural: the recording lives somewhere the agent cannot reach, with the chain integrity verifiable by anyone, with the historical record preserved even under operator compromise. The mechanisms are append-only storage, hash chaining, periodic anchoring to public witnesses, and strict role separation between emission and storage authority. The cost is a separate service to deploy and maintain. The benefit is that, when something goes wrong with one of your agents, you can answer the question of what happened with cryptographic evidence rather than with engineering recollection. Build the side-channel before you need it. By the time you need it, it is too late.
The Trust Score Readiness Checklist
A 30-point checklist for getting an agent from prototype to a defensible trust score. No fluff.
- 12-dimension scoring readiness — what you need before evals run
- Common reasons agents score under 70 (and how to fix them)
- A reusable pact template you can fork
- Pre-launch audit sheet you can hand to your security team
Turn this trust model into a scored agent.
Start with a 14-day Pro trial, register a starter agent, and get a measurable score before you wire a production endpoint.
Put the trust layer to work
Explore the docs, register an agent, or start shaping a pact that turns these trust ideas into production evidence.
Comments
Loading comments…