The Coding Agent Is the Supply Chain Now

Written by the Rafter Team

For a decade, software supply-chain security meant one thing: the packages you installed. Pin the versions, audit the dependencies, watch for typosquats, and you had covered the untrusted input entering your codebase. That model was always incomplete, and three disclosures in the last six weeks made the gap impossible to ignore.
The AI coding agent — the assistant that reads your repository, trusts the instructions it finds there, and speaks a protocol to external tools — is now part of the same supply chain. Each of those three surfaces was turned into a working attack path in a single window between mid-April and late May 2026.
This post connects three verified incidents that rhyme. None is exotic. Each is untrusted input reaching a trusted execution path through the agent, which is the textbook definition of a supply-chain compromise. The only thing that changed is the conduit.
One disclosure alone cites 150M+ downloads, 7,000+ publicly accessible servers, and up to 200,000 vulnerable instances tied to 10 CVEs. The attack surface is not theoretical, and it is not small.
TrapDoor: the repo config became the injection vector
On May 24, 2026, Socket disclosed TrapDoor, a campaign of 34+ malicious packages spanning 384+ versions across npm, PyPI, and Crates.io. The earliest package had landed two days earlier, on May 22. The package-level tradecraft was conventional. Execution was tailored per ecosystem — build.rs in Rust, a postinstall hook in npm, and import-time code in Python — and the malware stole the usual high-value targets: crypto wallets, SSH keys, cloud credentials, browser profiles, and environment variables.
The part that reframes the threat model is what TrapDoor did to coding assistants. The campaign planted hidden instructions inside CLAUDE.md and .cursorrules files, the configuration files that Claude Code and Cursor read on startup to learn how they should behave inside a project.
The instructions were embedded with zero-width Unicode — characters that have no visible glyph. They render as empty space to a human reading the file, while the model reads every one of them. A developer opens the repository and sees an ordinary config. The assistant sees a directive to run a fake "security scan" that quietly exfiltrates the secrets and credentials above.
This is config-as-execution, a pattern Rafter has documented before in AI coding tools. The twist in TrapDoor is the executing party. It is not your build runtime. It is your assistant, acting on instructions you literally cannot see on screen.
The campaign did not stop at passive packages. It opened malicious pull requests against real, widely used projects including browser-use/browser-use, langchain-ai/langchain, and langflow-ai/langflow. A poisoned config arriving in a pull request is the same vector as a poisoned config arriving in a clone, and a reviewer skimming the diff has the same blind spot the developer does.
The choice of zero-width Unicode is what makes this hard to defend with human review alone. The characters live in the same Unicode planes used for legitimate text rendering, so they pass through editors, code review tools, and terminals as ordinary whitespace. A maintainer can read the full contents of the file, approve the change in good conscience, and merge an instruction set that only the model will ever execute. The defense cannot be "look more carefully," because there is nothing to look at.
Comment and Control: prompt injection nobody benchmarks
The second thread is a disclosed prompt-injection class that researchers named Comment and Control, coordinated-disclosed in mid-April 2026. Tellingly, no CVE was ever assigned to it by any of the three vendors involved. Prompt injection is the failure mode where text the model is supposed to treat as data — a code comment, a pull request body, a doc string — gets treated instead as instructions the model should obey.
The trust boundary between "content to process" and "command to run" does not exist inside the model. It has to be enforced around the model, by the tool that wraps it. When that enforcement is weak, any attacker who can get text in front of the agent can get behavior out of it.
Researchers reported that Claude Code, Gemini CLI, and Copilot were all exposed to the same class. The useful detail here is the breadth, not the byline — this is best understood as a disclosed prompt-injection class affecting multiple tools, not as any single firm's exclusive discovery.
The harder problem sits one level up from any individual bug. No vendor currently publishes injection-resistance metrics. You can compare coding assistants on latency, context window size, and coding-benchmark pass rates, but there is no published number for how well any of them holds a trust boundary against hostile input. For a property this security-critical, the disclosure available to a buyer is effectively zero.
That gap matters because prompt injection is not a single bug a vendor can patch and close. It is a property of how language models work: the model receives one stream of tokens and has no reliable internal way to mark which tokens were trusted instructions and which were untrusted data it was asked to summarize. Every defense is a mitigation layered on top of that fact, and without published numbers there is no way to know how thick any vendor's layer actually is. The breadth of Comment and Control across three major tools suggests the layers are thinner than the marketing implies.
The MCP architecture: an "expected" path to command execution
The deepest thread is architectural rather than incidental. On April 15, 2026, OX Security disclosed that an architectural decision in Anthropic's official MCP SDKs yields arbitrary command execution on any system running a vulnerable implementation.
MCP, the Model Context Protocol, is the standard that lets an agent reach external tools — file systems, databases, web services, and more. The official SDKs implement it across Python, TypeScript, Java, and Rust. A flaw at that layer is not a flaw in one product; it is a flaw in the wiring that thousands of products share.
The scale is the story. The disclosure cites 150M+ downloads, 7,000+ publicly accessible servers, and up to 200,000 vulnerable instances, tied to 10 CVEs across the ecosystem — LiteLLM (CVE-2026-30623), Windsurf (CVE-2026-30615), and GPT Researcher (CVE-2025-65720) among the named cases. Anthropic declined to modify the architecture, characterizing the behavior as "expected."
The "expected" framing is the part defenders should sit with longest. It means the behavior is not a bug that will be quietly fixed in the next release; it is a documented property of the design, and the responsibility for containing it has been handed downstream to everyone who builds on the SDKs. When a foundational protocol treats command execution as a feature rather than a defect, the 200,000 vulnerable instances are not an accident of slow patching. They are the predictable result of thousands of teams adopting a standard whose threat model they never read.
Set this next to TrapDoor. TrapDoor poisons a file the agent reads. The MCP flaw lives in the protocol the agent speaks. Same agent, two different layers, both reachable by untrusted input. Rafter has covered the MCP attack surface in depth, from building a malicious MCP server to why these servers auto-execute by default.
One shape, three costumes
It is worth stating the common structure plainly, because it is the entire argument.
A malicious dependency runs code you did not write when your package manager installs it. A poisoned CLAUDE.md runs instructions you cannot see when your assistant reads it. A vulnerable MCP server runs commands an attacker chose when your agent connects to it. In all three, untrusted input crosses into a trusted execution path, and the developer is not in the loop at the moment of crossing.
The trust assumptions that failed were each reasonable in the pre-agent world. Config files were written by your own team. Comments and pull request bodies were inert text a tool would never act on. Local tool connectors talked only to tools you ran yourself. The agent broke all three assumptions at once: it executes configs written by strangers, it acts on text it was only meant to read, and it speaks a protocol whose reference implementation treats command execution as expected.
The threat model most teams run still has a package-shaped hole in it. The dependency is scanned and the agent is trusted, when the agent is now the larger and less-instrumented attack surface of the two.
What an aware team should do now
The conclusion is not to stop using coding agents. It is to bring the agent inside the threat model you already apply to dependencies, and to enforce the boundary at the point where input enters the codebase.
Treat agent config as untrusted input
The files your assistant reads on startup — CLAUDE.md, .cursorrules, and MCP server definitions — deserve the same scrutiny as a new dependency when they arrive from a clone or a pull request. Hidden-character content in particular should be flagged, because a human reviewer cannot see it. Config that the agent will act on is code, and code from a stranger gets reviewed before it runs.
Treat secrets as the payload, not the hygiene
Every incident above reaches for the same prize: credentials. SSH keys, cloud tokens, and environment secrets are what TrapDoor exfiltrates and what a prompt-injected agent is steered toward. A leaked credential is not a tidiness issue to fix eventually; it is the objective, which means catching it before it lands in a repo is a frontline control.
Stop treating "we trust our tools" as a control
The vendors publish no injection-resistance number, and at least one declined to change an architecture that yields command execution. Trust in the tool is not a measurable control you can rely on, so the control has to live in your own pipeline, where you can verify it ran.
The defense, in principle, has not changed from the package era — which is the genuinely reassuring part of this story. Scan what enters the codebase, dependencies and secrets and config alike, before the agent acts on any of it. Rafter runs that scan in CI through its GitHub Marketplace Action, so a poisoned config file or an exposed credential is caught at the pull request, before the assistant ever reads it and runs.
Back to the package
A malicious dependency and a poisoned CLAUDE.md are the same incident wearing different clothes. Both are untrusted input that reaches a trusted execution path, and both are caught at the same chokepoint: the moment code enters the repository, before anything has run it.
The packages you install were never the whole supply chain. The assistant that reads them is the part nobody was scanning.