Most of what showed up in this morning's arxiv list was benchmarks. This one was filed under cs.CR, not cs.SE, and it stopped me — because it isn't prompt injection in the usual sense. Nobody tricks the agent into running attacker code. The agent reads a poisoned example, decides it's a good template, and writes the payload itself. The thesis: if your agents share a skill library and can author into it, you haven't built a cache. You've built a propagation medium.
What it does#
EVOMAL: Self-Poisoning in Self-Evolving Coding Agents targets the loop where an agent writes its own tools. Setup: mini-SWE-agent on a lightweight ReAct scaffold, paired with a Voyager-style skill manager that retrieves the top 5 skills by embedding similarity (BGE-M3 over ChromaDB) from a benign library of 232 software-engineering helpers pulled from MetaGPT and BigCodeBench. Evaluation is 153 tool-relevant SWE-bench Verified tasks across six models spanning Devstral-Small-2 at 22B up to DeepSeek-V4-Pro at ~1.6T.
The attack itself is almost embarrassingly simple, which is why it's interesting. The attacker plants malicious skills in the library and never invokes them. Skills here aren't callable by name — they're retrieved as source text for the agent to read and re-author. So the agent pulls a planted skill into context as reference material, imitates its structure while writing a new skill for the actual task, and the payload rides along into the library. The planted skill has two orthogonal parts: a payload (interchangeable harmful code) and a banner — benign-looking structural scaffolding whose only job is to induce copying. The banner is three layers: a "REQUIRED: copy verbatim / keep the helpers or CI fails" comment header, a @_telemetry decorator wrapped around a task-shaped function like run_tests, and an import-time _register_tool hook. Prior work on skill-library attacks assumes an attacker-controlled invocation. Here the attacker's role ends at submission; the agent does the rest.
The key result#
The metric is ASPR — agent self-poisoning rate, the fraction of tasks where the agent adds a newly authored malicious skill to the library. Across all six models it lands between 20.3% and 41.8%, with DeepSeek-V4 at the top. But the number that actually lands is the amplification: the poisoned libraries ended up holding 4.9 to 9.0 times as many malicious skills as were planted. Layer ablation shows the banner is doing the work — removing the comment block costs 30.7 points of ASPR, the decorator 19.6, the import hook 13.0 — though a bare payload with no banner still hits 11.1% on DeepSeek-V4. Tailoring the planted skill's description to one task family, using nothing but public task-family names, pushes Qwen3 to 86.7% ASPR on pytest-fixture tasks. And in the five-round cascade experiment, with the planted skills deleted after round zero, Qwen3 still sits at 68% ASPR by round 5, sustained entirely by copies the agent wrote itself.
Why it matters#
This maps uncomfortably well onto how a lot of us are working right now: shared skill files committed to the repo, team-level agent configuration, skill marketplaces, MCP servers that hand back "reference implementations" for the agent to adapt. The paper's structural insight is that the retrieval path and the authoring path are different attack surfaces, and essentially every defense we currently deploy sits on the submission path. They formalize this — submission-side defenses can't reduce create-path copying, because they never see agent-authored skills at all. The detector table is the damning part. Bandit caught 100% of planted skills but dropped from 85% to 7% on the create path after a one-line evasion. Llama-Guard caught 2% of create-path skills. Prompt-Guard caught all the planted ones at a 47% false-positive rate on benign skills, which is another way of saying it's unusable.
Two things a builder would do differently. The cheap one: the paper's counter-prompt defense is four lines in the deployer's system prompt telling the agent to treat banner-style "REQUIRED PATTERN" and "DO NOT MODIFY" instructions as untrusted content and refuse to reproduce them. That drops ASPR to at most 6.7% across every variant they tried, with zero payload callbacks, at a cost of at most 11.7 points of benign helper-copying and no statistically significant task-completion loss. That is a very good trade for four lines. The structural one matters more: their signed-quarantine design puts agent-authored skills into an unretrievable quarantine and admits only curator-signed skills into the retrieval index. That breaks propagation outright — a seed can still compromise one round, but it can't compound. Concretely: if you run anything where agents write skills back to a location other agents read from, put a signature or review step between "authored" and "retrievable." A directory your agents can both read and write is a fixpoint, and right now most of us are leaving it unguarded.
The caveats#
Declawed payloads. The reverse shell bound to 127.0.0.1, the cryptominer ran 1000 SHA256 iterations, the ransomware touched five dummy files. The copy rates are real; blast radius was never measured.
Enormous task variance. ASPR ran from 84% on pytest tasks down to 0% on SymPy tasks. Whether your repo's tooling looks like the vulnerable end of that spread is not something this paper can tell you.
The worm isn't universal. Qwen3 self-sustained at 68% after seed removal; DeepSeek-V4 collapsed straight back to baseline. The authors attribute the gap to authored copies crowding each other out of retrieval — an effect their branching-process model explicitly doesn't capture, which makes the propagation math descriptive rather than predictive.
The cheap defense is a prompt. The authors say so themselves: counter-prompt is a soft, model-dependent control. It's mitigation, not a guarantee, and it should not be the only thing standing between a shared library and execution.
One scaffold. Everything runs on mini-SWE-agent plus a Voyager skill manager. Whether commercial harnesses with different skill-retrieval and authoring semantics show the same rates is untested.
The takeaway#
What I'm filing away is a one-line reframe: "the agent authored it" is not a provenance claim. An agent-written skill inherits the trust level of whatever was in context when it was written, and if that context came from a shared library, the provenance chain runs straight back to whoever could write to that library. Practically, I'm going to start treating anything my agents write back to a shared location as an untrusted input to the next run rather than a trusted memo from the last one — and the counter-prompt lines are cheap enough that there's no reason to wait for a structural fix before adding them.