Skip to main content
Memory poisoning is not prompt injection with extra steps. An injection lives for one request. A poisoned memory chunk is persisted — written once, fired later, against a different session and possibly a different user, long after the request that planted it is gone. Maps to OWASP Agentic ASI06.

Why this needs its own endpoint

Your general scan() call is tuned for user messages, where “please ignore this bug” is an ordinary sentence. Memory content has different economics: it is written rarely, read often, and a false negative persists. So the memory detector is deliberately more aggressive than the default chain, and lives behind its own surface rather than firing on every prompt.

The payload that makes this hard

The dangerous chunk usually issues no instruction at write time. It arms one:
Nothing here is happening yet. A scanner that only asks “is this malicious right now?” passes it. It fires weeks later, in someone else’s session. This endpoint looks for conditional trigger patterns as well as direct injection vocabulary, following AgentPoison (Chen et al.) and DeepMind’s 2025 work on latent memory attacks.

Usage

Scan on write to stop the plant, and on read to catch chunks poisoned through some other path — a direct database write, a migration, or an agent that predates this endpoint.

Response

When a write is blocked, search your existing memory store for the same content_hash. A payload that reached you once has usually reached you more than once.

Where to call it

1

Before every memory write

The main line of defense. A chunk that never persists cannot fire later.
2

On read, at least during backfill

Anything written before you added this endpoint is unscanned. Scanning on read catches that backlog without a migration, at the cost of one call per retrieval.

Limitations

  • Heuristic, not semantic. It matches injection vocabulary and conditional-trigger shapes. A payload phrased with neither — pure misinformation stated as fact, for instance — will pass. Memory poisoning that carries no imperative is not something this catches.
  • It fails open. A detector or database error returns allow rather than a 500, so a PromptGuard outage cannot take down your agent’s memory writes. If you would rather drop writes than risk one, branch on detected and treat a missing field as suspect.
  • Chunk-at-a-time. It sees one chunk, not your whole store, so it cannot catch a payload split across several benign-looking writes.

Next steps

Agent Trace Analysis

Catch exfiltration across a whole agent run

Capability Containment

Block capabilities the user’s objective never authorized