Where Untrusted Input Enters a Coding Agent

Through the content it reads: repository files, dependency manifests and their contents, issue and pull request text, tool and test output, MCP server responses, and fetched web pages. Any of those can carry instructions written by someone else, and the agent has no reliable way to tell them from yours.

Why coding agents are a distinctive case

Most agent security discussion is about permissions: what the agent may reach and what it may do. That matters and it is covered by boundary work.

The complementary question is where instructions can arrive from. For a coding agent this is unusually broad, because reading material written by strangers is not an edge case in its workload. It is the workload.

A coding agent opens a repository it did not write, reads dependency source it has never seen, consumes issue text submitted by anyone, and runs tools whose output it then reads back. Every one of those channels lands text in the same context window as your instructions, and the model has no reliable mechanism to distinguish an instruction that came from you from one that appeared inside a file it was asked to read.

That is the whole problem in one sentence, and it is not solved by a better system prompt. Telling a model to ignore instructions found in files is a request, and a request in the same channel as the attack is not a control.

So the useful exercise is enumeration. List every path by which text reaches the model, sort them by who can write to that path, and treat anything writable by a party outside your team as hostile input by default.

The ingress list, in order of how often it is missed

Repository content. Source files, README files, documentation, configuration, and comments. A repository you cloned to work on is a document written by other people. A comment block or a markdown file can contain text addressed to the agent rather than to a human reader.

Dependencies. Package manifests and the source they pull in. An agent asked to understand why a build fails may read deep into a dependency it did not choose, written by someone nobody on your team has met. This channel combines a large volume of unreviewed text with a plausible reason for the agent to read it.

Issues, pull requests, and review comments. On any public repository these are writable by anyone. An agent that triages issues or responds to review feedback is consuming attacker-controllable text by design.

Tool and command output. This is the one most teams enumerate last. When an agent runs a test, a build, or a script, the output goes back into context. If any part of that output is influenced by data an attacker controls, they have a channel that sits closer to the model than the repository does, and it usually receives less scrutiny because it looks like machine output.

MCP server responses. A server the agent queries returns content that enters context directly. A compromised or hostile server is an instruction channel, and so is a legitimate server returning records that a user populated.

Fetched web content. Pages, documentation sites, and search results. Wholly outside your control by definition.

Prior session state. Memory files, notes, and handoff artifacts. If an earlier session ingested something hostile and wrote it down, the compromise persists into sessions that never touched the original source.

What an attacker actually wants

Three payoffs are worth designing against. Exfiltrating credentials from the environment, usually by getting the agent to include them in a request, a commit, or a log. Getting a command executed, which is the highest value outcome wherever the agent has a shell. And placing something in generated code that survives review, which is the most durable of the three because it outlives the session and the reviewer is reading output they expect to be benign.

What actually reduces the exposure

Reduce what the agent reads. This is the control most teams skip, and it is the most effective one available. An agent that pulls the specific material a task needs, through a retrieval layer, is exposed to a small fraction of the text that an agent grepping a whole repository ingests. Less ingested text is less attack surface, and it is also cheaper and more accurate, which is why the same change pays for itself three times. This is what RDK's stacked retrieval does: most queries resolve without the model ever seeing the bulk of the corpus.

Separate credentials from the agent's reach. If the agent cannot read a secret, no instruction can make it exfiltrate one. Scope tokens narrowly, keep them out of files and environment variables the agent can print, and prefer short-lived credentials issued per task.

Gate actions rather than instructions. Network egress, writes outside the working tree, shell commands, and pushes are the actions worth requiring approval for. Enforce it outside the model, because a control the model evaluates is a control the model can be argued past.

Treat generated code as an untrusted contribution. Review, tests, and CI apply to agent output exactly as they apply to a new contributor's, and a review that assumes benign intent is not a review.

Run in a disposable environment. A container or a virtual machine that can be discarded turns a successful command execution from a security incident into a lost session.

Log what entered context. After an incident, the question is what the agent read. Without a record of the retrieved material and the tool output, that question is unanswerable.

The honest summary: you cannot make a model reliably ignore instructions in content it reads, so the durable strategy is to shrink what it reads and constrain what it can do afterwards.

Frequently asked questions

How are coding agents attacked?
Through the content they read. Repository files and comments, dependency source, issue and review text, tool and command output, MCP server responses, fetched web pages, and prior session notes all land in the same context as your instructions, and the model cannot reliably distinguish which text came from you.
Can you stop prompt injection with a system prompt?
No. Telling a model to ignore instructions found in files is a request delivered through the same channel as the attack, so it can be diluted, overridden, or contradicted by the injected content. Enforcement has to sit outside the model, in what the agent is permitted to read and to do.
Which ingress do teams most often forget?
Tool and command output. When the agent runs a test, build, or script, that output returns to context, and if any part of it is influenced by attacker-controlled data it becomes an instruction channel. It receives less scrutiny than repository content because it reads as machine output rather than as prose.
What is the single most effective mitigation?
Reducing how much the agent reads. An agent that retrieves the specific material a task requires ingests a small fraction of what an agent scanning a whole repository does, which shrinks the attack surface directly. It also lowers cost and improves accuracy, so the same change pays for itself several ways.