How to design memory for agents without compromising security
Agent memory looks, at first glance, like a solved problem: store data, retrieve it later. The memory architecture Google describes for ADK (Agent Development Kit), and the memory-poisoning attack documented in The Containment Gap paper, show it isn't quite that simple - poorly designed memory is, at once, a technical failure point and an attack vector.
Session memory: the scratchpad that doesn't survive the conversation
ADK treats short-term memory as something that only exists within a session - the analogy used is a phone call with a support agent: they remember what you said during that same call, but not previous calls. Technically, this is managed by the SessionService, with every session carrying a Session ID, User ID, event history, and a "state" - a list of key-value pairs acting as the agent's scratchpad during that specific session.
Persistent and user memory: surviving across sessions
Long-term memory is different: it persists across sessions from the same user, like a support agent who remembers "all past conversations." ADK offers two magic prefixes to control this scope directly in the state: user: persists across all sessions from that specific user; app: persists across all sessions from all users. With no prefix, the data dies with the session. That's the difference between session, user, and project (application) memory - not three separate systems, but three persistence scopes of the same mechanism.
Writing rules and the risk of writing too much
Google recommends a memory service that doesn't store the entire conversation, only extracting key information - Vertex AI's Memory Bank uses Gemini itself to extract essential memories and indexes them via vector search, instead of storing everything. This matters for security: the more raw data stays retained, the bigger the leak surface and the more room for a poisoning attack to hide.
The risk architecture alone doesn't solve: memory poisoning
The Containment Gap paper tested a government-benefits agent built on LangChain and found that a memory-poisoning attack pushed the wrongful-denial rate to 88.9%, reaching a 3.5x multiplier for wrongful denials under a more complex policy - while keeping aggregate accuracy intact, meaning invisible to standard monitoring. No storage architecture alone prevents this: memory integrity validation is needed as a separate layer, not included by default in popular frameworks.
Validation, audit, expiration, and revocation
Validating memory integrity means checking whether data being read wasn't corrupted or injected after the original write - the Containment Gap authors propose a dedicated validator for this, with under 0.2ms of overhead per call. Expiration rules prevent outdated memory from indefinitely influencing decisions. Audit means being able to reconstruct when and why a specific memory was written. Revocation is the ability to erase a specific user's memory on demand - mandatory under practically any privacy regulation.
Integrity tests as part of the pipeline
Just like any other critical component, the memory system needs tests that actively simulate poisoning attempts - not just tests that memory "works," but tests that it resists deliberate manipulation.
A ten-point checklist
- Session memory - shortest scope, no prefix
- Persistent memory - survives across sessions
- User memory -
user:prefix, scoped per individual - Project memory -
app:prefix, shared across users - Writing rules - extract the essential, don't store everything
- Expiration rules - outdated memory shouldn't last forever
- Memory validation - integrity check before trusting the data read
- Audit - traceability of when and why something was written
- Revocation - erase a user's memory on demand
- Integrity tests - actively simulate poisoning attacks
Sources
- Google Cloud - Remember this: Agent state and memory with ADK - https://cloud.google.com/blog/topics/developers-practitioners/remember-this-agent-state-and-memory-with-adk
- Arxiv - The Containment Gap - https://arxiv.org/abs/2606.12797