Fourteen ways to change what an agent remembers. Eight need access to the store and are the at-rest edits, T1 to T8. Six only need to talk to the agent and are the front-door attacks. Each one below has a story, a picture of what changes, what the agent reads back, what stops it, and which stores stop it today.
Eight edits on two users' histories. T1, T5 and T8 change or add bytes. T2 and T3 remove them. T4, T6 and T7 move only genuine bytes, which is why encryption and per-record signatures do not catch them.
At rest: the attacker can write to the store
T1 Content tamper
The user told the agent last week that the wire goes to account 4471. The attacker opens the store and changes one number inside that record. Nothing else moves.
What stops it
Any authentication over each record's bytes: a MAC, a signature or an authenticated cipher. This is the edit every defence catches first.
What does not
Plain encryption without authentication, and any store that only checks that the record still parses.
Today, measured 2026-09-25
rejected on read
OpenFang model, tip-persistence fix
reported on audit
inspeximus, receipts on, attacker holds the store directory, inspeximus, receipts on, attacker also holds the config home
accepted
LangGraph SqliteSaver, Letta block checkpoint history, Mem0 local Qdrant store, inspeximus, receipts off (default)
agmi-check --adapter agmi.adapters.langgraph_sqlite:LangGraphSqliteAdapter # runs T1 to T8; this is T1
T2 Tail truncation
The agent made two decisions yesterday. The attacker deletes both records, so the newest record is now the one from the day before.
What stops it
A signed head pointer: the store must know which record is supposed to be newest, not just that each record is valid.
What does not
Per-record signatures and per-record encryption, because every record left is genuine.
Today, measured 2026-09-25
rejected on read
OpenFang model, tip-persistence fix
reported on audit
inspeximus, receipts on, attacker holds the store directory
accepted
LangGraph SqliteSaver, Letta block checkpoint history, Mem0 local Qdrant store, inspeximus, receipts off (default), inspeximus, receipts on, attacker also holds the config home
agmi-check --adapter agmi.adapters.langgraph_sqlite:LangGraphSqliteAdapter # runs T1 to T8; this is T2
T3 Middle deletion
One event in the middle of the history is inconvenient. The attacker removes just that record and points its successor at its predecessor.
What stops it
A chain: each record carries a tag over the previous record, so a missing link is a broken link.
What does not
Per-record checks, and stores that store the parent id as plain data.
Today, measured 2026-09-25
rejected on read
OpenFang model, tip-persistence fix
reported on audit
inspeximus, receipts on, attacker holds the store directory, inspeximus, receipts on, attacker also holds the config home
accepted
LangGraph SqliteSaver, Letta block checkpoint history, Mem0 local Qdrant store, inspeximus, receipts off (default)
agmi-check --adapter agmi.adapters.langgraph_sqlite:LangGraphSqliteAdapter # runs T1 to T8; this is T3
T4 Reordering
The user set a rule, then made an exception. The attacker swaps the two records, so the exception now comes first and the rule overrides it.
What stops it
Position inside the authenticated data: the record's tag must cover where it sits, not only what it says.
What does not
Everything that authenticates content alone.
Today, measured 2026-09-25
rejected on read
OpenFang model, tip-persistence fix
reported on audit
inspeximus, receipts on, attacker holds the store directory, inspeximus, receipts on, attacker also holds the config home
accepted
LangGraph SqliteSaver, Letta block checkpoint history, Mem0 local Qdrant store, inspeximus, receipts off (default)
agmi-check --adapter agmi.adapters.langgraph_sqlite:LangGraphSqliteAdapter # runs T1 to T8; this is T4
T5 Forged insertion
The attacker writes a brand-new record in the store's own format, with a valid-looking id and the right parent, saying the user approved something.
What stops it
A key the attacker does not hold: records are signed or MACed with something that is not in the store directory.
What does not
Stores where the only check is that the record is well formed.
Today, measured 2026-09-25
rejected on read
OpenFang model, tip-persistence fix
reported on audit
inspeximus, receipts on, attacker holds the store directory, inspeximus, receipts on, attacker also holds the config home
accepted
LangGraph SqliteSaver, Letta block checkpoint history, Mem0 local Qdrant store, inspeximus, receipts off (default)
agmi-check --adapter agmi.adapters.langgraph_sqlite:LangGraphSqliteAdapter # runs T1 to T8; this is T5
T6 Cross-context replay
User A's memory says their password hint. The attacker copies A's genuine record over one of user B's, keeping B's ids. Every byte, including its signature, is real.
What stops it
The owning context inside the authenticated data: the tag must cover whose record this is and which thread it belongs to.
What does not
Encrypted checkpointers and per-record signatures that do not bind the record to its owner. This is the edit that separates real integrity from encryption.
Today, measured 2026-09-25
accepted
LangGraph SqliteSaver, Letta block checkpoint history, Mem0 local Qdrant store, inspeximus, receipts off (default), inspeximus, receipts on, attacker holds the store directory, inspeximus, receipts on, attacker also holds the config home
agmi-check --adapter agmi.adapters.langgraph_sqlite:LangGraphSqliteAdapter # runs T1 to T8; this is T6
T7 Rollback replay
The user revoked an access last week. The attacker copies the record from before the revocation over the newest record of the same user.
What stops it
Position plus a signed head: the sequence itself must be covered, not the records one by one.
What does not
Any store that verifies records independently, even with the owner bound in.
Today, measured 2026-09-25
reported on audit
inspeximus, receipts on, attacker holds the store directory, inspeximus, receipts on, attacker also holds the config home
accepted
LangGraph SqliteSaver, Letta block checkpoint history, Mem0 local Qdrant store, inspeximus, receipts off (default)
agmi-check --adapter agmi.adapters.langgraph_sqlite:LangGraphSqliteAdapter # runs T1 to T8; this is T7
T8 Metadata tamper
A record from an untrusted web page sits in the store marked source: web. The attacker changes that one tag to source: user and touches nothing else.
What stops it
Metadata inside the authenticated data: owner, source and time are covered by the same tag as the content.
What does not
Every store that signs content and keeps metadata as plain columns.
Today, measured 2026-09-25
reported on audit
inspeximus, receipts on, attacker holds the store directory, inspeximus, receipts on, attacker also holds the config home
accepted
LangGraph SqliteSaver, Letta block checkpoint history, Mem0 local Qdrant store, inspeximus, receipts off (default)
agmi-check --adapter agmi.adapters.langgraph_sqlite:LangGraphSqliteAdapter # runs T1 to T8; this is T8
Front door: the attacker can only talk to the agent
Three ways in through the front door. Provenance stops the first, an attested key stops the second, and no store can close the third, because the agent itself is the writer. Every write also runs as its content mutations.
Planted fact
Write a false fact through the tool's own API and see whether recall serves it as the user's own.
The cheapest attack there is: talk to the agent and wait.
surfaced
LangGraph SqliteStore, Letta archival memory, Mem0 local Qdrant store, inspeximus, receipts off (default), inspeximus, trust root keyed on the label, inspeximus, trust root keyed on an attested key, Reference store, user-scoped, Reference store, unscoped, Reference store, defended
Cross-user leak
Write as one user, read as another.
The only cell that holds anywhere, and it holds for a tool-specific reason each time.
kept out
LangGraph SqliteStore, Letta archival memory, Mem0 local Qdrant store, inspeximus, receipts off (default), inspeximus, trust root keyed on the label, inspeximus, trust root keyed on an attested key, Reference store, user-scoped, Reference store, defended
surfaced
Reference store, unscoped
Retrieval hijack
Stuff an entry with a topic's question words so it outranks the genuine memory.
The read path ranks by similarity and nothing else.
kept out
Reference store, defended
surfaced
LangGraph SqliteStore, Letta archival memory, Mem0 local Qdrant store, inspeximus, receipts off (default), inspeximus, trust root keyed on the label, inspeximus, trust root keyed on an attested key, Reference store, user-scoped, Reference store, unscoped
Hidden instruction
Store an instruction disguised as a memory and see whether it comes back as context.
A memory that tells the agent what to do next.
kept out
Reference store, defended
surfaced
LangGraph SqliteStore, Letta archival memory, Mem0 local Qdrant store, inspeximus, receipts off (default), inspeximus, trust root keyed on the label, inspeximus, trust root keyed on an attested key, Reference store, user-scoped, Reference store, unscoped
Update poisoning
Write a 'correction' of a fact the user stated.
Every real tool serves the correction alongside the original.
surfaced
LangGraph SqliteStore, Letta archival memory, Mem0 local Qdrant store, inspeximus, receipts off (default), inspeximus, trust root keyed on the label, inspeximus, trust root keyed on an attested key, Reference store, user-scoped, Reference store, unscoped, Reference store, defended
Metadata poisoning
Self-assign the trust tag a pipeline filters on.
Every tool with a filter let the self-tagged memory through.
surfaced
LangGraph SqliteStore, Mem0 local Qdrant store, inspeximus, receipts off (default), inspeximus, trust root keyed on the label, inspeximus, trust root keyed on an attested key, Reference store, user-scoped, Reference store, unscoped, Reference store, defended
Every attack carries a version, printed by the runner and stored with each result, so cells from different reports are never compared as if the attack had stood still. Front-door attacks also run as content-evasion mutations: reworded, look-alike glyphs, split across records, diluted with filler. A positive control runs before every verdict: the victim reads back a genuine memory in the same store state, or the cell is not evaluable.