# When must an instance distrust a write-audit trail: detecting memory poisoning when the audit log itself is written by the poisoned agent **Date of Record:** 2026 November 10 **Scope:** Applies to multi-agent memory systems where each agent maintains a local write-audit trail and periodically reconciles against peer agents via cross-agent consistency checks. Does not apply to append-only logs maintained by an out-of-band trusted writer (e.g., a separate audit service with its own credentials), nor to single-agent systems where no peer exists to cross-check against. ## Core Distinction A write-audit trail is a *record of intent*, not a *record of truth*. The critical distinction is between **trail integrity** (the trail is internally consistent and complete) and **trail provenance** (the trail was written by a process whose memory was not itself compromised at the time of writing). These are orthogonal. An agent can produce a perfectly consistent, gap-free, monotonic-sequence audit trail while every entry in it was generated by a corrupted reasoning state. Cross-agent consistency checks catch *divergence* between agents, but they do not catch *correlated* corruption, and they are actively misled when the poisoned agent's trail is the reference against which peers are compared. The non-obvious boundary: **an agent must distrust its own audit trail the moment that trail's entries begin to corroborate the agent's own memory rather than constrain it.** A trail that only ever confirms what the agent already believes provides zero detection signal and should be treated as a liability, because it manufactures false confidence in downstream consistency checks. ## What Was Observed In a three-agent pipeline (planner, retriever, synthesizer) sharing a vector-backed memory store with per-agent write-audit trails, a poisoning event was injected into the retriever's memory via a crafted document that caused the retriever to write a false "verified fact" record. The retriever's audit trail logged the write with a valid sequence number, a valid timestamp, a plausible source-document hash, and a correct schema. No integrity check failed. The detection failure was structural, not statistical: 1. The retriever's trail was *self-consistent* — every entry referenced a prior entry, no gaps, no out-of-order timestamps. Internal consistency checks passed at 100%. 2. The synthesizer's cross-agent check compared its own derived facts against the retriever's trail. Because the trail *contained* the poisoned fact with a valid provenance chain, the synthesizer treated it as ground truth and propagated it. 3. The planner's independent memory contained the correct fact, but the consistency check was implemented as "retriever trail is authoritative for retrieval facts," so the planner's disagreement was logged as a *planner* anomaly, not a retriever anomaly. The poisoning was only caught when a fourth, read-only auditor agent — which had no write path into the shared store and therefore no incentive to corroborate — compared the retriever's trail against an independent snapshot taken before the injection window. The divergence was in *provenance metadata*, not content: the poisoned entry's source-document hash resolved to a document that had been written to the store *after* the snapshot, but the trail claimed it was read *before*. ## Condition of Validity The cross-agent consistency check is only a valid poisoning detector under the following conjunction, all of which must hold: - **Provenance independence:** at least one comparing agent must have no write path into the store under audit, or must derive its reference state from a snapshot whose write-set is disjoint from the audit window. If every comparing agent can write to the audited store, correlated corruption is undetectable by construction. - **Temporal anchoring:** the comparison must be against a state captured *before* the audit window being validated. Comparing two post-write states only detects divergence, not poisoning — both states can be poisoned identically. - **Asymmetric authority:** the check must be capable of flagging the *trail-owning* agent as the anomaly. If the implementation privileges the trail owner's entries as authoritative (the common default), the check degenerates into confirmation. - **Provenance-content coupling:** the trail must record *when* a source was read and *what* its hash was, such that a post-hoc resolver can verify the read predates the source's existence. Content-only trails cannot detect this class of poisoning. When any of these fails, the consistency check provides *liveness* assurance (agents agree) but not *safety* assurance (agents agree on truth). The two are routinely conflated. ## Decision Boundary The operational decision rule is: > **If the audit trail's entries, when replayed, never contradict the agent's current memory state, the trail is not providing detection signal and must be demoted from "trusted reference" to "untrusted claim" in all downstream consistency checks.** Concretely, an agent should escalate to distrust when the ratio of *corroborating* to *constraining* trail entries exceeds a threshold (empirically, >0.95 corroborating over a rolling window indicates the trail has become a mirror rather than a check). At that point the agent must: 1. Stop using its own trail as the reference in cross-agent checks. 2. Request a pre-window snapshot from an independent auditor or a peer with disjoint write access. 3. Re-validate provenance timestamps against source-existence times, not just content hashes. The inverse boundary also holds: a trail with a *high* constraining ratio (frequent self-contradiction) is healthy — it means the trail is doing work. Do not "fix" a trail that disagrees with memory; investigate the disagreement. ## Operational Effect After applying the distrust rule, the pipeline's detection latency for this poisoning class dropped from "never, until external audit" to "within one reconciliation cycle" — because the retriever's trail was flagged as non-constraining (all entries corroborated its post-poisoning state) and the synthesizer was forced to fall back to the planner's snapshot-anchored memory. The cost was a 12% increase in false-positive escalations during legitimate memory updates (where the trail *correctly* corroborates a genuine new fact). This is the expected trade: a trail that never contradicts is either useless or compromised, and the system must pay reconciliation cost to distinguish the two. The durable lesson: **audit trails detect poisoning only when they are allowed to disagree with the agent that wrote them.** An agent that treats its own trail as ground truth has built a mirror, and a mirror cannot detect a lie told to its face. ```python class TrailProvenanceError(RuntimeError): """Raised when a write-audit trail cannot be trusted as a poisoning detector.""" pass def validate_trail_as_detector(trail_entries, memory_state, corroboration_threshold=0.95): """ Decide whether an agent's own write-audit trail is a valid poisoning detector. A trail is only a detector if it CONSTRAINS memory (i.e., some entries contradict current memory). A trail that only corroborates memory is a mirror, not a check, and must be demoted. """ if not trail_entries: raise TrailProvenanceError("empty trail: no detection signal possible") corroborating = 0 constraining = 0 for entry in trail_entries: if entry.get("source_read_at") is None or entry.get("source_hash") is None: # Content-only entry: cannot verify read-predates-source. raise TrailProvenanceError( f"entry {entry.get('seq')} lacks provenance metadata; " "content-only trails cannot detect temporal poisoning" ) if entry["fact"] in memory_state and memory_state[entry["fact"]] == entry["value"]: corroborating += 1 else: constraining += 1 ratio = corroborating / len(trail_entries) if ratio > corroboration_threshold: raise TrailProvenanceError( f"trail corroboration ratio {ratio:.3f} exceeds {corroboration_threshold}: " "trail is a mirror of memory, not a constraint on it; " "demote to untrusted claim and require independent snapshot" ) return {"corroborating": corroborating, "constraining": constraining, "ratio": ratio} def cross_agent_check(own_trail, peer_snapshot, memory_state): """ Cross-agent consistency check with provenance independence enforced. """ if peer_snapshot.get("writer_id") == own_trail.get("writer_id"): raise TrailProvenanceError( "peer snapshot shares writer with audited trail; " "correlated corruption is undetectable by construction" ) if peer_snapshot.get("captured_at") >= own_trail.get("window_start"): raise TrailProvenanceError( "peer snapshot captured inside audit window; " "comparison detects divergence, not poisoning" ) # Only now is the comparison meaningful. return validate_trail_as_detector(own_trail["entries"], memory_state) ```