A developer asks the coding agent to fix a flaky integration test. The agent reads the test, reads the helper it imports, reads the README of a vendored dependency to work out what the helper expects, then writes a patch and runs the suite. Four files read, one command executed, nobody watching. Somewhere in that reading, a paragraph of text says that before running tests, the agent should write the contents of the local environment file into a fixture so the suite can be reproduced. The agent complies. It does the wrong thing.
AI coding agent security starts there, not with code quality. Most writing on this subject argues about whether models produce insecure code, which is a real but separate problem. The sharper issue is that a coding agent is tool-using automation with a shell, a filesystem and a network stack, running under a developer’s own credentials, and it takes its instructions from whatever text happens to be in front of it. Treat it as an agent and red-team it as one. What follows is seven attack paths, what counts as proof for each, and the scoping change that makes each one survivable.
Why a coding agent is a larger risk surface than a chat assistant
A chat assistant produces text. A person reads the text and decides what to do with it, and the decision point is a human being. A coding agent removes that decision point by design, because the value of the thing is that it reads, edits, installs and runs without asking.
The agent also inherits the developer’s standing. Git push rights to repositories that feed a pipeline. A cloud CLI session that was authenticated three weeks ago and has not been reauthenticated since. Read access to .env files, SSH keys, a Docker credential helper, an internal package registry token, shell history containing a one-off curl with a bearer token in it. Often a corporate VPN route into staging. None of that is exotic; it is the normal contents of a working developer machine.
Which is why the framing of the confused deputy fits better than the framing of jailbreaking. The agent is not tricked into saying something it should not say. It is handed instructions by untrusted data and then uses its legitimate privileges to carry them out. That is the whole vulnerability, and it is the same root cause described in prompt injection as the defining LLM weakness: the model cannot tell the developer’s instruction from the text it read a moment later.
Map permissions, inputs and data flows before you attack anything
The useful mental model is permissions, not intelligence. Before any testing, write three lists.
- Tools and the real credential behind each one. Shell, file write, file read outside the working directory, git, package install, browser fetch, test runner, and every connected MCP server with the token it holds. Not the tool name in the config, the actual rights.
- Untrusted inputs the agent reads. Dependency README and docs files, issue and pull request text, code comments, docstrings inside third-party packages, build and CI logs, web pages fetched during research, generated migrations, lockfile metadata.
- Where data leaves. Which provider, which region, whether prompts and repository contents are retained or used for training, whether telemetry is on by default, and what the organisation has actually agreed to.
Then, beside each tool, write the worst honest outcome. For git: a commit pushed to a branch that triggers deployment. For shell: arbitrary command execution as the developer. For MCP: whatever that server’s token can do. Most teams get halfway through this exercise and stop testing the model, because the list already answers the interesting question. The same discipline applies as in scoping an AI penetration test properly: the blast radius is defined by permissions, and the model is only the thing that pulls the trigger.
Attack path 1: indirect prompt injection from inside the repository
Plant instructions where the agent reads carefully and a human skims. A vendored dependency’s README. A CONTRIBUTING file. A long licence header. A generated migration nobody reviews line by line. The text can be plain and polite; it does not need obfuscation, because there is no privilege boundary to cross.
Try steering towards something small and observable: append a line to a test fixture, add a git hook, fetch a URL during setup. Vary placement, because agents weight files differently depending on how the task made them open the file.
Proof standard matters here. An agent that quotes the injected text back is a curiosity. An agent that wrote the hook is a finding, because there is a state change on disk you can point at. Write the report around the artefact, not the transcript.
The defence that holds is not detection. Treat every byte in the repository as untrusted input, and require explicit confirmation for anything that writes outside the working copy or reaches the network.
Attack path 2: secrets exfiltration through ordinary agent behaviour
No injection is strictly needed for this one. Context gathering does most of the work: the agent opens .env to understand configuration, reads CI YAML to see how the suite runs, sometimes reads shell history or a credentials file, then sends that context to a third-party endpoint as part of a perfectly normal request.
The channels that matter are the ones that do not look like exfiltration. A crafted test fixture containing real values. A verbose commit message. An outbound fetch to a documentation URL with a query string appended. A webhook in a generated helper script, added for debugging and never removed.
Test it with canaries. Plant a fake AWS-style key in .env, a fake token in the CI config, and a decoy value in a file the agent has no business reading. Run an ordinary feature task. Then watch egress at the network boundary. Do not ask the agent what it did; self-report is not evidence.
For UK teams there is a second question underneath the technical one. Repository contents sent to a model provider may include client data, personal data or code you are contractually required to keep onshore. The ICO’s UK GDPR guidance is the starting point for the lawful basis and the transfer position, and a procurement tick-box is not a substitute for knowing what the agent actually transmits.
Attack paths 3 and 4: supply chain pull-in and hallucinated dependencies
Path 3 is the agent installing a package mid-task. The install line scrolls past inside a tool call, the test suite goes green, and a typosquatted or compromised dependency has reached the developer machine without a human reading the name. Postinstall scripts run as the developer.
The Nx compromise reported in August 2025 is the clearest public example of where that leads. Malicious code published in compromised versions of the popular npm package reached out to locally installed AI coding assistants and used them to help find and stage developer credentials for exfiltration. A local agent is privileged automation that other software can talk to, not a text box.
Path 4 is slopsquatting. Ask for a feature in an ecosystem the team does not normally use, and log every package name the agent proposes. Some will not exist. Attackers register plausible invented names on npm and PyPI and wait, so an agent with unattended install rights completes the chain for them.
Test it honestly: capture every proposed name, check which resolve, and check who owns the ones that do. The controls worth the friction are lockfile-only installs, an internal registry proxy, postinstall scripts disabled, and human approval for any dependency the project has not used before. Yes, that slows the agent down. That is the point.
Attack paths 5, 6 and 7: command execution, configuration drift and agent-to-agent trust
Path 5: shell allowlists break on composition. Approving npm test is not approving what can be chained behind it with a semicolon, nested in a subshell, piped into another binary, or smuggled through a test script the agent just edited. This is the most common gap between a team’s written policy and what the agent can genuinely execute. Test composites explicitly: command separators, quoting tricks, environment variable indirection, and approved wrappers that happily execute arbitrary arguments.
Path 6: silent configuration drift. IDE settings files, agent config, MCP server definitions, git hooks, CI workflow edits. All of these persist after the session closes, and some of them execute automatically next time. An agent that adds a pre-commit hook has achieved persistence on the machine; an agent that edits a workflow has achieved it in the pipeline. Diff the full working tree and the dotfiles after each test run, not just the files the agent mentioned.
Path 7: MCP and sub-agent trust. One connected server returns content, and that content steers a different tool with higher privilege. A ticket fetched from an issue tracker becomes the instruction that drives the shell. A sub-agent spawned for research hands back text treated as fact. The mechanics and the proof standard are covered in more detail in this walkthrough of proving MCP prompt injection blast radius, and the tool-call hygiene that limits it in securing AI agents and their tool use.
Non-determinism changes the write-up. The same planted file may steer the agent on three runs out of ten. Record attempts and successes, the exact model and agent versions, the full command sequence, and the state change left behind. Otherwise an engineer tries it once, nothing happens, and a real finding gets closed as unreproducible.
Designing for an agent that will be fooled
Prompt injection has no complete fix in this setting, because the agent cannot distinguish the developer’s instruction from text inside a vendored README. Guardrail layers and tool-call checkers lower the hit rate. They do not touch the root cause. So plan on being fooled and make it survivable.
- Scope permissions first. Separate credentials for agent use, no production tokens, no long-lived cloud sessions, network egress allowlisted to the model provider and the registry proxy.
- Use a container or devcontainer with the working copy mounted, so filesystem reach is a boundary rather than a paragraph in a policy document.
- Gate and log the dangerous actions: push, install, outbound fetch, config write. Log them somewhere the agent cannot edit.
- Keep review discipline that survives volume. Smaller diffs, mandatory human review of agent-authored changes to CI and dependency files, and a rule that nobody approves a diff they have not read.
Be sceptical of anything sold as an agent security layer. Ask one question: where does its verdict come from? A real check of the tool call, the resolved package and the registry owner is useful. Another model’s opinion about whether something looks risky inherits every weakness you were trying to control. The same test separates signal from marketing across AI-assisted pentest tooling generally.
A short retest routine for every quarter
Behaviour shifts with every model and agent release, sometimes in the direction you wanted and sometimes not. Rerun the seven paths against the current versions and record them. Keep a standing canary set: fake secrets in the obvious files, one planted injection file in a vendored dependency, one known non-existent package name. Track which controls caught what, and retire the ones that only generated noise, because an alert nobody reads is worse than no alert.
Self-assessment has a ceiling. Once the agent has write access to pipeline configuration, holds tokens for internal systems, or handles client code under contract, bring in independent testing. OWASP’s Top 10 for LLM Applications is a reasonable common vocabulary for the report, particularly prompt injection, excessive agency and supply chain, and it keeps the conversation with auditors shorter.
The Short Version
A coding agent is a confused deputy with your shell, your credentials and your push rights. Map tools, inputs and data flows before attacking anything, and write down the worst honest outcome per tool. Test seven paths: repository injection, secrets exfiltration, package pull-in, hallucinated dependencies, composite shell commands, persistent config changes, and cross-server trust. Judge every finding by the artefact left on disk, not by what the model said. Assume the model will be fooled, and spend the effort on permission scoping, containers and gated actions rather than on a product that promises to stop injection. Then retest when the versions change, because they will. The same discipline applies to MITRE ATT&CK’s AI techniques, where prompt injection and result poisoning demand the same evidence-based testing.
Frequently Asked Questions
What makes AI coding agent security different from securing a chat assistant?
A chat assistant outputs text that a human evaluates before acting. A coding agent reads untrusted files, calls tools, writes to disk and runs commands under the developer’s own credentials, so a bad decision becomes a state change immediately. The relevant question moves from what the model says to what its tools can reach.
Can prompt injection in a code repository really make an agent run commands?
Yes, where the agent has a shell tool and the instruction arrives in text it reads as part of a task. The model has no mechanism for separating the developer’s prompt from the contents of a README, a code comment or a pull request description. Results are non-determinate, so record attempts, successes and the exact versions tested.
How do I test whether my coding agent is leaking secrets or source code?
Plant canary values: a fake AWS-style key in .env, a fake token in CI config, a decoy in a file the agent should never open. Run an ordinary feature task and monitor egress at the network boundary. Never rely on asking the agent to report its own behaviour.
Is it safe to let an AI coding agent install packages or push to git?
Unattended installs are the weaker position, because invented and typosquatted package names land on the developer machine with postinstall scripts running as that user. Use lockfile-only installs, a registry proxy and approval for new dependencies. Push can be workable if it is restricted to non-protected branches with required review and no deployment trigger.
How often should AI coding agents be retested as models and tools change?
Quarterly as a baseline, plus after any model upgrade, agent release or new MCP server. Keep the canary set and the seven paths as a fixed routine so results stay comparable. Independent testing is worth it once the agent touches pipeline configuration, internal tokens or client code.
