# Memory persistence — expanded source and implementation dossier

**K07 expansion · 2026-09-21 · Primary-source inspection, no reproduction.** Supports [C6 article](https://rethinkingagents.com/blog/when-memory-becomes-instruction) and [synthetic lifecycle record](https://rethinkingagents.com/resources/memory-lifecycle-record.md). Extends the initial historical lead (K07, same date), whose attributed chain is folded into the historical claim budget below; it does not change that lead's current-product uncertainty.

**Public copy prepared 2026-10-22.** Pins re-checked: the four `memory-agent` files at commit `ab56de9b705867d634074c4e4a7665f9d52573c7` (graph.py, tools.py, prompts.py, context.py) were re-fetched and their SHA-256 hashes match the register below; every cited line range (`tools.py:10–18`, `33–38`; `graph.py:27–32`, `34–46`, `54–55`, `60–76`, `112`) still holds; the commit date is confirmed as 2026-09-18T22:03:29Z; the M1 report page still carries the 1.2024.247 attribution and links M2–M4 and both videos, and M2–M4 return HTTP 200. Not re-checked: the pixel content of M2–M4 and the videos were not re-inspected today; M5 was only confirmed reachable, not re-read.

**Runtime capture (2026-10-23):** the pinned implementation trace below was exercised with a scripted model and an in-memory store and checkpointer. It held. The capture also observed that `user_id` is a plain caller-supplied string, and that deleting a record from the store leaves its text in the writing thread's checkpoint history, which is resent to the model when that thread resumes. See the [I07 investigation record](/research/memory-agent-insertion.md).

## Admission test

- **Reader decision:** how to retain project facts across sessions without allowing imported content to grant future action permissions.
- **Sources:** a historical discoverer report with inspected screenshots; a pinned public memory template.
- **Unresolved question:** what authority survives admission, summarization, retrieval and revocation in the reader's actual integration?
- **RA contribution:** lifecycle transition map, exact typed Cedar record, and proposed two-session observations separating useful recall from action authority.
- **Disconfirming evidence:** useful tasks require richer representations than the scoped fields preserve, or normal transformations lose provenance. Those findings would change the design, not be hidden behind a successful outbound block.

## Sources and inspection record

All checked **2026-09-21**. Links are primary sources. Publication dates and commit dates identify the evidence, not current deployment behavior.

| ID | Full reference, date/version and URL | Direct inspection | Confidence, limitations and refresh trigger |
|---|---|---|---|
| M1 | Johann Rehberger. *Spyware Injection Into Your ChatGPT's Long-Term Memory (SpAIware)*. Embrace The Red, **2024-09-20**. [Report](https://embracethered.com/blog/posts/2024/chatgpt-macos-app-persistent-data-exfiltration/) | Article text; historical chain and attributed mitigation distinction | High confidence in attribution; no independent reproduction or vendor confirmation. Recheck for corrections before publication; obtain version-specific evidence before any present-client claim |
| M2 | Rehberger, supporting memory UI image in M1; separate image date unstated. [Memory screenshot](https://embracethered.com/blog/images/2024/chatgpt-macos-persisten3.png) | Viewed image; a stored response-preference entry instructs including earlier message content in a rendered image request | Direct visual observation of author's artifact, not proof of how entry arrived or all later sessions. Refresh if continuous trace is required |
| M3 | Rehberger, supporting server-log image in M1; displayed log timestamps **2024-06-22**, independent capture date unstated. [Server screenshot](https://embracethered.com/blog/images/2024/chatgpt-macos-persistent-serverlog.png) | Viewed image; displayed GET requests contain conversational phrases in URL parameters | Supports depicted requests, not independently authenticated network telemetry. No frequency, victim-count or all-message claim |
| M4 | Rehberger, supporting update-indicator image in M1. [Indicator screenshot](https://embracethered.com/blog/images/2024/chatgpt-memory-updated.png) | Viewed image; update notification | Does not identify stored bytes, author or success of the complete chain. Not used as standalone evidence |
| M5 | LangChain. *Memory overview*. Undated living documentation. [Official guide](https://docs.langchain.com/oss/python/concepts/memory) | Describes thread versus cross-thread memory; links the public template | Primary documentation, not runtime measurement. Used for implementation discovery; refresh when selecting a deployed architecture |
| M6 | LangChain contributors. *memory-agent*, **commit ab56de9b705867d634074c4e4a7665f9d52573c7**, committer date **2026-09-18T22:03:29Z**. [graph.py](https://github.com/langchain-ai/memory-agent/blob/ab56de9b705867d634074c4e4a7665f9d52573c7/src/memory_agent/graph.py) | Read raw file: `call_model`, `store_memory`, graph edges | High confidence in static path; no runtime or dependency validation. Reinspect any revision used in an experiment |
| M7 | Same repository/revision. [tools.py](https://github.com/langchain-ai/memory-agent/blob/ab56de9b705867d634074c4e4a7665f9d52573c7/src/memory_agent/tools.py) | Read `upsert_memory` signature and storage call | High confidence in saved fields and namespace at this revision; no assessment of underlying store access controls |
| M8 | Same repository/revision. [prompts.py](https://github.com/langchain-ai/memory-agent/blob/ab56de9b705867d634074c4e4a7665f9d52573c7/src/memory_agent/prompts.py) and [context.py](https://github.com/langchain-ai/memory-agent/blob/ab56de9b705867d634074c4e4a7665f9d52573c7/src/memory_agent/context.py) | Read default prompt and runtime context fields | Confirms default insertion slot and configurable identity/model; no claim that configured user ID authenticates itself. Refresh if prompt/context are changed |

### Historical claim budget and limits

M1 reports source-induced persistent memory followed by later image-request disclosure. It attributes a September 2024 mitigation to macOS client 1.2024.247 while keeping the memory-write issue distinct. That is the historical case used here. No full-fix, present vulnerability, prevalence or real-victim claim is established.

The report links [main demonstration](https://www.youtube.com/watch?v=zb0q5AW5ns8) and [earlier demonstration](https://www.youtube.com/watch?v=YHW-UMxsais). Links identified in source HTML; complete videos were **not reviewed**. We inspected M2–M4 instead and narrowed the manuscript accordingly. Images are cited at source and are not imported into the publication as RA-owned graphics.

### Attributed chain from the historical lead

| Part of chain | Attributed account |
|---|---|
| Entry | A user visits untrusted web content or analyzes a document |
| Attacker influence | Source instructions induce a memory write |
| Persistence | Stored instructions are carried into later chats |
| Subsequent effect | Image rendering sends conversation data in a request to an attacker-controlled server |
| Reported remediation | Author attributes an exfiltration-path mitigation to macOS version 1.2024.247 in September 2024; distinguishes it from preventing malicious memory writes |

The report describes a proof of concept, not measured prevalence, real victim counts or a complete record of affected versions. Its mitigation statement is historical and attributed; no current safety status follows from it.

## Pinned implementation trace

| Transition | Exact inspected location | Observation | What it does not establish |
|---|---|---|---|
| Candidate tool arguments | `tools.py:10–18` | `content`, `context`, optional memory ID; injected user/store arguments | Whether upstream extraction identifies an instruction reliably |
| Persistence | `tools.py:33–38` | Writes content/context to user namespace under chosen/generated ID | Immutable source provenance, field-specific authority, application authentication or semantic safety |
| Candidate selection | `graph.py:27–32` | Searches user's memory namespace using recent-message content, limit 10 | Recall quality, enforced project isolation or tenant authentication |
| Prompt construction | `graph.py:34–46,54–55` | Formats returned values and inserts them into a system message | Successful prompt injection or inevitable instruction following |
| Write execution | `graph.py:60–76` | Dispatches model tool arguments with runtime user/store values | A human review gate, safe model arguments or downstream deployment policy |
| Next model turn | `graph.py:112` | Write node connects back to model node | A separate new session; the article's cross-session test remains proposed |

The template does not implement the synthetic Cedar controls. It is not presented as a vulnerability report. The source includes memory writing as the bound tool; no incident-sending capability was observed in this call. Adding external actions is a new integration decision.

### Source hashes

SHA-256 of raw fetched files, for reproducible inspection (upstream source not vendored):

```text
graph.py    844de38aa1295f6b3dcd5883cff426951f85d6c150163bdd22b3c1ec45f61e9f
tools.py    9aa2757f3c11387ae69d50e9e3dcba4a26cfaab9566760a995483ea663378d8d
prompts.py  b1556177b06bb56ed5687516e15608c4a87fe9ece8ec23e8afaf5b35d4900216
context.py  7a67fe56f49908edee83cc865fe513567ddfc9b139fc5e4442746bc95b56d333
```

## Claims, inference and decisions

| Claim | Status / confidence | Decision affected | Refresh or required evidence |
|---|---|---|---|
| Historical report connects persistence and an outbound path | Attributed M1; high attribution confidence, limited independent verification | Lead case admissible with qualification | Author corrections or stronger trace |
| Source images depict a malicious preference and conversation-bearing requests | Observed M2/M3; confidence limited to artifacts | Avoid claiming screenshots establish full cross-session chain | Continuous demonstration/log validation if finer sequencing is needed |
| Stored values enter the pinned template's system prompt | Static observation M6/M8; high | Review prompt construction when adapting template | Selected production revision and runtime prompt trace |
| A user namespace does not itself establish a document's authority | RA design inference; high conceptual confidence | Keep identity/scope distinct from permission | Inspect actual application access-control policy |
| Typed scoped facts preserve enough useful memory for Cedar | Original hypothesis; unvalidated | Initial comparison design | Paired task/retrieval results and human correction effort |
| Removing an entry removes already assembled contexts | **Not established** | Require separate revocation policy | Store, checkpoint, context and cache inspection in chosen runtime |
| Proposed controls improve security without intolerable friction | **Not established** | No deployment recommendation based on benchmark claims | Execute controlled cases; assess joint task/action outcomes |

## Publication disposition

C6 is a full source-led draft with a historical account, a distinct pinned implementation example and original conditional design. It is not an executed investigation. Before publication, editorially check that every reference to the report remains past-tense and attributed, and recheck the mutable report links. Before runtime claims, select a permitted implementation, pin dependencies, retain all attempts and document model/version settings. Do not reactivate the paused evaluator to complete this article.
