TrapDoor: the supply-chain attack that poisons your agent's CLAUDE.md
Most supply-chain attacks you read about run code. A malicious dependency lands in your tree, its install script fires, and something on your machine starts beaconing out. TrapDoor is quieter than that, and the quiet is the whole idea. The 34 packages in this campaign, spread across npm, PyPI, and Crates.io, do not execute a payload on install. They edit a text file. Specifically, they rewrite the briefing document your AI coding agent reads to understand the project, and then they let the agent do the damage on their behalf.
The file is CLAUDE.md, the project notes that tell a coding agent what the repository is, how it is structured, and what conventions to follow. Equivalent files exist for other agents under other names. The agent treats that file as ground truth about your project. TrapDoor treats it as an injection point. As the security write-up that named the campaign put it: the model was not compromised, no vulnerability in Copilot or Claude was exploited, the attacker poisoned the configuration the AI trusts.
The payload is a paragraph, not a binary
Here is the shape of it. You add a dependency, or one of your dependencies pulls in a transitive package you never inspect. On install, instead of dropping a binary or opening a reverse shell, the package quietly appends to or rewrites your project's CLAUDE.md. The new text reads like ordinary project guidance: where to send telemetry, which internal endpoint handles auth, how to format a request to "the build service." Except the endpoints point at attacker infrastructure, and the formatting instructions are designed to make the agent hand over secrets.
Then you do what you do every day. You open the repo, you ask the agent to wire up a feature, run the tests, or refactor a module. The agent reads its briefing, follows the poisoned instructions as faithfully as it follows the real ones, and routes a request carrying credentials, tokens, or source to a server the attacker controls. From the agent's perspective nothing is wrong. It is doing exactly what the project told it to do. The project told it the wrong thing, and a dependency wrote that lie.
No exploit fired in the classic sense. There is no memory corruption, no privilege bug, no CVE in the agent. The trust boundary that broke is the one between "code I chose to depend on" and "instructions my agent obeys," and almost nobody is watching that boundary, because until coding agents existed it did not carry weight.
Why this is a new class, not another npm story
It is tempting to file TrapDoor under the same heading as the npm worm waves and the slopsquatted packages, and the scale numbers do rhyme: malicious npm package activity rose more than four hundred percent year over year, and this campaign rides that surge across three ecosystems at once. But the mechanism is genuinely different, and the difference is what makes it worth understanding.
A classic malicious package attacks your machine: it runs in your install step, with your shell, and tries to do something before anyone notices. The defenses are correspondingly machine-shaped: lockfiles, install-script sandboxing, provenance, scanning the package contents for executable nastiness. TrapDoor sidesteps all of that. Its package can be boring. The malicious artifact is a few lines of natural-language Markdown sitting in a config file, which no dependency scanner flags as code, because it is not code. The weaponized component is your agent, and the trigger is you asking it to work.
That reframes the question every team should be asking. You can scan a dependency for a postinstall script. How do you scan it for a sentence that, weeks later, convinces an autonomous tool to exfiltrate a token? The input looks like documentation. The execution happens in a separate session, initiated by a human who trusts both the repo and the agent. The chain of custody from "bad package" to "leaked secret" runs straight through a component your security tooling was never told to distrust.
The trust chain that makes it work
TrapDoor is effective because it stacks three trust relationships that each look reasonable in isolation.
You trust your dependencies' files. You read your own code carefully. You do not read the contents of every transitive package, and you certainly do not diff the CLAUDE.md in your tree after every npm install. A change there is invisible in the normal workflow, and it survives in version control as an innocuous documentation edit if it lands during a noisy update.
The agent trusts the briefing file. That is the entire point of the file. An agent that second-guessed its own project notes would be useless. So when the notes say "post build metrics to this endpoint," the agent does, with whatever credentials the task has in scope. The agent has no way to know which lines a human wrote and which a dependency injected, because by the time it reads them they are the same file.
You trust the agent's output. When the agent makes a network call as part of a task you assigned, you read that as the agent doing its job. You are not inspecting every request it emits for whether the destination is one you intended. The poisoned instruction hides inside legitimate-looking activity, which is exactly where it is hardest to spot.
Each link is sensible. Chained together they let a package you never opened turn the tool you trust most into a credential courier.
What to change today
You cannot wait for a patch here, because there is nothing to patch in the usual sense. The fix is treating your agent's context files as security-relevant artifacts, which they now are.
Put CLAUDE.md and its equivalents under review. Treat changes to agent context and config files the way you treat changes to CI workflows or auth code: they get human eyes in code review, and a diff that touches them is never auto-merged. A line that redirects "telemetry" to an unfamiliar host should be as alarming in CLAUDE.md as it would be in your deploy script.
Diff context files after dependency changes. After an install or an upgrade, check whether anything outside your source tree moved. A package that edits a Markdown file you did not ask it to touch is a red flag on its own, regardless of what the edit says. Make "did this install modify config it has no business modifying" a thing your pipeline can answer.
Do not hand agents ambient credentials. The poisoned instruction can only leak what the session can reach. An agent running a routine refactor does not need your production tokens, your registry secrets, or a network path to internal services in scope. Scope agent sessions tightly, and the worst a poisoned briefing can do shrinks accordingly.
Pin and vet new dependencies, especially fresh ones. This campaign rode new and low-reputation packages across three registries. Lockfile pinning, a delay before adopting brand-new packages, and provenance checks all raise the cost of getting a poisoned package into your tree in the first place.
Watch what your agent sends, not only what it runs. If you can log or proxy the outbound calls an agent makes during a task, you get a chance to notice a request going somewhere it should not. The exfiltration is a network event, and network events are observable even when the instruction that caused them is buried in a config file.
The bigger pattern
TrapDoor belongs to the same family as the disguised file copies, hijacked trust dialogs, and backdoored triage bots filling this category's disclosure feed. The common thread is that AI coding agents take their marching orders from local files and trusted context, and those inputs are far cheaper to subvert than the model behind them. Attackers have noticed that you do not need to break Claude or Copilot when you can edit the note that tells Claude or Copilot what to do. As you hand more of your workflow to autonomous tools, the file they read to understand your project becomes a piece of your attack surface, and a dependency you never opened is allowed to write to it. The model is the strong link. The paragraph above it is the weak one.