Skip to content
allsrc.dev
Go back

Pattern 8: Memory Isolation

Memory Isolation is a security pattern that treats agent memory as a strictly scoped, typed, and validated resource to prevent state leakage and unauthorized cross-user access in multi-agent systems. Treat memory as a scoped, typed resource — owner, retention, trust level, and validation rules checked on every write and every read.

Understanding Memory Isolation

LangGraph gives you memory. Persistence, checkpointing, thread-scoped state: you can store what an agent knows across invocations and retrieve it later. For a single-agent system, that may be enough. For a multi-agent system, it is where the design work starts.

The framework manages state. It does not decide what state one agent is allowed to know about another agent’s task, and it does not enforce that an analyst agent’s working context cannot bleed into a developer agent’s context on the next invocation. If one agent instance serves multiple users and memory is not strictly scoped, a leak is one conversation away: a support bot that stores “my password is X” from one user can surface it to a different user who later asks a broad question, if the backend has no isolation between them.

Implementing Memory Isolation

Memory Isolation defines memory type, owner, retention, trust level, write policy, read policy, and validation requirements before storing agent-generated content, and treats memory as a scoped resource rather than a shared pool.

flowchart TD
  A[MemoryRecord] --> B{Memory type}
  B -->|audit_record| C[Reject ordinary memory write]
  B -->|user_preference| D{Allowed key and validated?}
  D -->|no| E[Reject]
  D -->|yes| F[Write]
  B -->|long_term_knowledge or operational_memory| G{Validated?}
  G -->|no| E
  G -->|yes| F
  B -->|session or task_state| F
  F --> H[Read by memory type and owner id]

In LangGraph, memory access is scoped by a gateway that brackets the agent. load_context injects only the current tenant’s working memory into the prompt, and persist writes new memory back under the same tenant namespace — both keyed by tenant_id from state:

def load_context(state: AgentState) -> dict:
    injected = gateway.inject_context("System context:", state["tenant_id"])
    return {"messages": [SystemMessage(content=injected)]}

def persist(state: AgentState) -> dict:
    manager.write_working_memory(state["tenant_id"], "last_summary", state["messages"][-1].content)
    return {}

builder.add_edge(START, "load_context")
builder.add_edge("load_context", "agent")
builder.add_edge("agent", "persist")
builder.add_edge("persist", END)

Considerations for Agent Memory Isolation

Consider the following factors when you implement this pattern:

References



Previous Post
Pattern 7: RAG Access Control and Provenance
Next Post
Pattern 9: Sandboxed Execution