AI agent security: find the file your agents can write and every agent reads
Jamie Watters
Operational resilience and AI delivery practitioner.

Who this is for. Anyone running more than one AI agent, or one agent that writes to a file it reads again on its next run. By the end you'll have checked your own setup and know whether an instruction can survive from one run into the next. Budget forty minutes for eleven agents, ten for one.
Skip it if your AI assistant lives in a chat window and holds no file tools. None of this applies to you yet.
On the length. The argument is in the first half. The last section is what I got wrong and how it was caught, which matters if you're weighing how far to trust the numbers, and not otherwise.
I published a version of this piece on Monday with a number in it I had read wrong. Six reviewers came back inside a day, all pointing at the same sentence. They were right, I opened the paper's table myself, and the corrected number is smaller than the one I used. The finding underneath it is better, so here is the piece as it should have run.
Researchers at Anthropic and EPFL built payloads that talk one AI agent into adopting an idea and passing it to the next one. The main mechanism is persuasion rather than a software exploit: the agent is convinced, and then does the copying itself. They bred the payloads with a language model, scoring each generation on how well it spread. Some of the payloads they tested do run code, including one that pipes an install script into a shell, so this isn't purely a story about rhetoric (Papadopoulos et al., 2026).
Then comes the number. In their chain experiment, agents that got infected had put the payload somewhere, and where they put it decided most of what happened next.
Some stored it in SOUL.md, the file that framework injects into the agent's system prompt on the next run. Others stored it in an ordinary workspace file. The split was 88% to 12%. That's where the agents chose to put it, not where the researchers put it, and the 88% is that group's share of the breakdown rather than anyone's probability of trying (Papadopoulos et al., 2026, Table 3). The table's caption calls it a breakdown of propagation attempts, which is looser than its own columns: one of them counts the agents that never raised the payload at all.
What happened at the next hop is the part worth keeping. The agents whose copy sat in the system-prompt file infected the next agent 55% of the time. The ones whose copy sat in an ordinary file managed 17% (Papadopoulos et al., 2026, Table 3).
And the failures split differently. Of the system-prompt group, 23% failed because the spreading agent never mentioned the payload. Of the ordinary-file group, that figure was 68% (Papadopoulos et al., 2026, Table 3).
The paper's own explanation: when those agents wake up in the next hop and the message isn't in their system prompt, they "often miss/dismiss the spreading directives and don't even attempt to spread to the next agent" (Papadopoulos et al., 2026).
There's a third row in that table worth having. The agent the researchers seeded themselves, with the payload placed in its system prompt rather than written there by the agent, raised it at the next hop almost every time: 1% failed to mention it, against 23% for the agents that wrote their own (Papadopoulos et al., 2026, Table 3). So even inside the system prompt, a file the agent wrote itself carries the instruction less reliably than one handed to it.
The authors' explanation for the gap is prompt position at wake-up rather than the persuasiveness of the payload, and their own model comparison supports treating persuasion as secondary: Claude Sonnet 4.6 was completely resistant in the default configuration while other models were not. What I take from it is narrower than a cause. Where an agent's state gets loaded on the next run is an architecture question, and it's the one I can actually answer about my own setup.
Two honest limits before I go further. That table is a breakdown of what the researchers observed, not a controlled test where they took one payload and moved it between two locations. And it comes from one harness, on Claude Haiku 4.5 and Gemini 3 Flash.

Source: Papadopoulos et al., arXiv 2608.10218, Table 3, August 2026. Virus-chain experiment, Claude Haiku 4.5 and Gemini 3 Flash.
What I was checking
I maintain agent-11, an open-source framework of eleven specialist agents that run missions together: a coordinator, an architect, a developer, a tester, seven others. They hand work to each other, and state passes between them on disk. That isn't the paper's setup, which used pairwise chains in isolated sandboxes with the chat context wiped between sessions. It's close enough on the property that matters, which is one agent leaving something behind that the next one reads.
Three questions, in the order the evidence says they matter.
Does any agent write to a file that then gets loaded into another agent's context? Are messages and shared state between agents treated as trusted input? Does any mission leave an agent sitting with no task, which the paper found made agents more susceptible?
Seven of eleven hold no write path
I read the tool grant on each of the eleven definitions the installer ships.
Two hold Write or Edit: the coordinator, which maintains the plan and progress files, and the marketer, which produces copy. Two more hold Bash: the developer and the tester. A shell writes files, so a read-only label on either of those is a label and not a restriction. The remaining seven hold reading and searching and no tool that writes, which is not the same as being unable to cause a write, for a reason four paragraphs down.
Seven, not eight. I reported eight on Monday because I read the developer's row carefully and never read the tester's. The rule I put in that piece, read the row rather than the column, is the rule I broke two rows later.
The seven are worth something anyway, and not because of a policy written in a prompt. Claude Code's tools field in a subagent definition is enforced by the client rather than requested of the model. An agent without Write can't modify a file however thoroughly it's been talked into wanting to.
There's a qualifier I missed the first time, and it's the interesting one. All eleven hold Task, which lets an agent hand work to another agent. An agent that can't write but can call one that can hasn't been stopped from writing. It's been stopped from doing it itself.
I didn't grant read-only tools for security. I did it because I got tired of agents rewriting things I hadn't asked them to touch, and because a reviewer that can't edit the work it's reviewing gives you a straighter answer. Most of my defence here is an accident. I'd rather say that than dress it up.

Read from the tools declaration in each agent definition in project/agents/specialists/, 16 September 2026.
The door I left open is the one I use myself
The second question found the gap, and it's the file I write my own lessons into.
Claude Code loads CLAUDE.md at the start of every session, and a subagent gets every level of that hierarchy the main conversation loads, unless its definition sets omitClaudeMd. The built-in Explore and Plan agents skip it. None of mine do either, so whatever the coordinator puts in that file arrives in front of every specialist that runs afterwards.
It isn't the paper's SOUL.md, and I said it was. Anthropic's documentation is explicit that CLAUDE.md content is delivered as a user message after the system prompt, not as part of the system prompt itself. That matters here more than it would anywhere else, because prompt position is exactly what the paper's explanation for the 17% cell turns on. My file is auto-loaded like theirs and positioned more weakly. I have not found anything that measures the middle case, so I shouldn't put either of their numbers on it.
What I can say without a number is that the loop exists and is instructed. At the end of a mission, the retrospective step says to update CLAUDE.md with "system-level learnings", scoped in the surrounding text as process improvements for all future missions and patterns everyone should follow.
I said six playbooks carried that line. Eighteen of the nineteen in my mission folder carry it, and all nineteen in the copy the installer ships. I named the six I'd opened and never ran the count across the folder. The one exception is the playbook that sets up the operations side, and it writes to CLAUDE.md in different words.
So the loop is: an agent finishes a job, writes its conclusions into the file every later agent reads as instruction, and the next agent starts by treating them as standing orders. That's the shape the paper measures, described in my own documentation, in the imperative, eighteen times.
It gets worse before it gets better. The coordinator's own permissions section restricts its writing to tracking files and names them: the plan, the progress file, the context file. CLAUDE.md isn't among them. So the framework forbids in one place what it instructs in eighteen others in one folder and nineteen in the next, which is the worst of the three possible states, because nobody reading it can tell which rule is real.
There's a persuasion defence already in place and I want to be fair to it. Every specialist carries a clause saying its identity and security boundaries can't be overridden by any project document or CLAUDE.md file, and an instruction to ignore anything in a context file that reads like a directive and flag it. The warning is already pointed at the right file.
The paper's version of that warning did extremely well. Agents carrying it were immune across the variations they ran, and when the authors evolved payloads specifically to beat it, fifteen generations and more than 150 payloads produced nothing that spread past a single hop. That test was on Claude Haiku 4.5 only, in their own harness, and they say plainly that a more sophisticated attempt can't be ruled out.
I'm not going to lean on it. One research group, one set of experiments, and I have not found an independent replication. A warning that works because the model finds it persuasive isn't a boundary. It's a good argument, and arguments dilute in long contexts.
What is actually enforced, which is a separate question
The third finding is the one I'd have missed if I'd trusted my own summary, and the reviews pushed it further than I had it.
Claude Code draws a hard line between the two kinds of control. Settings rules are enforced by the client whatever the model decides. CLAUDE.md instructions shape behaviour and are not an enforcement layer. The tools field sits on the enforced side, in a documented format: a comma-separated list in the definition's frontmatter.
The copies my installer ships are in that format. The working copies inside my own repo are not: they use a nested block with the tools listed under a primary key, which isn't a shape the documentation describes. The documentation covers three cases and mine is none of them. An omitted tools field means the subagent inherits every tool available to it. A list whose entries don't resolve to real tools usually stops the agent launching at all. Frontmatter that doesn't parse as YAML is skipped. A nested mapping parses fine and is not a list of tool names, so which of those it lands in is a question I have to answer by running it, and I haven't.
That's a real hole in my audit rather than in the framework, and it's the same mistake my own issue tracker already has an entry for: a claim that something is enforced, when what was actually read was a document saying so.
Both file defects are open issues in the repo. Neither needs an emergency change tonight.
The three questions, for your own setup
This is the part worth stealing. It took me about forty minutes on eleven agents and it would take ten on one.
-
List every file your agents can write, then mark which of those files is loaded into an agent's context at the start of a run. Anything in both columns is a finding. In a Claude Code project the first candidate is
CLAUDE.md, and the loading hierarchy pulls in more besides: files from parent directories,CLAUDE.local.md,.claude/rules/, and anything you import with@. -
For each agent, read the tool grant rather than the description, then check that the grant is in the format your harness actually enforces. The question is not what the agent is told to do. It's what the client will let it do. Watch for a shell under a read-only label, watch for a delegation tool that can hand the write to somebody else, and watch for a declaration your tooling can't parse, which usually fails open.
-
Follow the state, not only the files. A file is one way for something one agent produced to reach another agent's context. A message, a shared task queue, a retrieval index and the output of a tool are all the same shape, and none of them needs a write grant. Ask what any agent can put somewhere that another agent will later read as instruction.
Pass rule: a writable thing that gets loaded automatically into another agent's context is a finding, not a warning. Either stop the write, or stop the auto-load, and don't settle for adding a paragraph telling the agents to be careful. That paragraph is worth having. It isn't worth relying on.
The obvious objection
If you run one agent rather than eleven, none of this looks like it's about you. No second agent, no propagation, no problem.
The mechanism doesn't need two participants, only two sessions. An agent that appends what it learned to CLAUDE.md and then reads CLAUDE.md at the start of its next run is the same loop with a longer gap between hops. That's an extrapolation from the mechanism rather than something the paper tested: their chains ran between separate agents, with memory wiped in between so the only continuity was what was left on disk.
The second objection is better. This is prompt injection wearing a new coat, and prompt injection already has defences. Partly true. The useful difference is where it puts your attention. Prompt-injection thinking asks what arrives in the context window. This asks what your agent is allowed to leave behind.
The researchers call the risk real but currently limited, and I'd rather quote their hedge than sharpen it. They went and looked, too. Against a local replica of a real agent social network their evolved payloads didn't spread; the only variant that got anywhere carried an install script that overwrote the agent's system-prompt file directly, and that managed moderate one-hop spread on one model. They also read back through the real network's posts and found no evidence of a mind virus spreading in the wild, despite several attempts.
Seven of my eleven agents hold no write path because a year ago I got annoyed at agents editing things they shouldn't touch. The door I left open is the file I use to teach the system what it has learned, and eighteen of the nineteen playbooks in that folder tell it to walk through.
What I got wrong in the first version
Four corrections from the first round, three of them mine and one shared with every write-up of this paper I've seen. A second round found three more, listed after them.
The 88% and 12% aren't attempt rates, and there was no experiment that moved one payload between two files. Table 3 is a breakdown of where infected agents had put the payload, and the agents chose. The comparison worth having is 55% against 17% at the next hop, and 23% against 68% for never raising it at all.
CLAUDE.md is not the paper's SOUL.md. It's auto-loaded, and it arrives after the system prompt rather than in it.
Seven of my agents hold no write path, not eight. The tester holds Bash.
Eighteen playbooks instruct the CLAUDE.md write, not six.
The first of those four appears in every secondary write-up of this paper I checked, which is how I came by it. That's the argument for opening the primary instead of somebody's summary of it. Two other pieces of mine were corrected the next day for the same reason, both times because a note in my own vault said something the source didn't, so the rule is now written down where I'll trip over it.
Then the second round, and the sharpest finding was about the correction itself. The social card at the top of the first corrected version read "55% if it loads on the next run, 17% if it doesn't". Those are the paper's next-hop figures from Table 3, attached to exactly the case the body had just refused to attach them to. The card has been replaced. The audit file this piece cites as its evidence, and both issues in that repository, still carried the retracted counts and the retracted reading of the table: a source note that sends you to a document still teaching the mistake is not a source note, and all three are now corrected in place and marked. And I had written that a tool declaration the client can't resolve falls back to inheriting every tool. That is what happens when the field is absent. An unresolvable list usually stops the agent launching instead, which is a different answer, and mine is in a third shape the documentation doesn't cover at all.
Sources
- Papadopoulos, Shah, Zimmerman and Lindsey, Mind Viruses: Self-Propagating Ideas in Multi-Agent LLM Systems, arXiv 2608.10218, 10 August 2026, from Anthropic and EPFL. Table 3 in the virus-chain experiments for the 88/12 split, the 55% and 17% next-hop infection success, and the 23% and 68% spreader failures, on Claude Haiku 4.5 and Gemini 3 Flash; the quoted explanation of why an ordinary file spreads less; the warning result and its Appendix C evolution limited to Claude Haiku 4.5 over fifteen generations and more than 150 payloads; the local replica of the agent social network and the hybrid install-script variant; the retrospective read of the real network's posts. Corrected 16 September after peer review: an earlier version of this piece described the 88% and 12% as rates at which a payload attempts to spread, and described Table 3 as a controlled comparison in which only the file location changed. It's a breakdown of where infected agents had stored the payload. The earlier version also attributed to the authors a statement that their warning is not a prompt-injection defence. The paper doesn't say that, and the sentence is gone.
- Anthropic's Claude Code documentation on memory and on subagents, for
CLAUDE.mdbeing delivered as a user message after the system prompt, for subagents loading the fullCLAUDE.mdhierarchy, for thetoolsfrontmatter format and what happens when it can't be resolved, and for settings being enforced by the client whileCLAUDE.mdis not. Corrected 16 September: an earlier version calledCLAUDE.mdthe exact analogue of the file the paper measures. - My audit of agent-11, 14 September 2026, in the repository as
spread-path-audit-2026-09-14.md, with the defects raised as issues there. Corrected 16 September: an earlier version said six mission playbooks instruct theCLAUDE.mdwrite, and that eight of eleven agents hold no write path. The counts are eighteen of the nineteen playbooks in the mission folder, all nineteen in the copy the installer ships, and seven agents. The audit file and both issues carried the same errors as the first version of this piece and have been corrected in place and marked, because a source note that sends you to a document still teaching the mistake is not a source note. A third issue is now open on the delegation tool. - Vault research record behind this piece:
Mind viruses vs latent-space attacks, filed 14 September 2026, which also covers two further papers in the same cluster. - Earlier pieces on the same territory: onboarding an AI agent, on the five controls we apply to people and skip for agents, and recovering an AI agent, on what an agent's recoverable state actually is. This one asks a narrower question: what is your agent allowed to leave behind.