Prompt Injection Awareness
Security · Working with AI
There is one sentence at the bottom of this whole problem: a language model cannot reliably tell the difference between instructions you gave it and instructions it found inside the content it read.
Everything else follows from that. No one is about to fix it, because it is how these things work. Text arrives in the context window and the model treats it as text. There is no separate channel that says "this part is the job, this part is just data you are looking at." Prompt injection is what happens when someone puts instructions in the data.
It has been the top item on OWASP's list of language-model risks for a while, and it is still there in 2026, not because nobody is trying, but because the fix is not a filter. What has changed is the cost of being wrong. When the model could only produce text, an injection got you a rude answer. Now the model can run commands on your laptop.
The gradient of how bad this gets
Not all exposure is equal, and it is worth being precise about why.
In a chat tab. You paste a page into a chat window, the page carries hidden instructions, and the model does something you did not ask for. It gives a wrong answer, or a biased summary, or tries to talk you into visiting a link. That is bad. It is also mostly bounded: the damage is in the reply, and you are sitting right there reading it.
The bound weakens as soon as the assistant gets connectors. Give it your email, your drive, your calendar, and a way to make outbound requests, and a hostile document can get it to fetch something private and send it somewhere. Both Microsoft 365 Copilot and ChatGPT's connectors had zero-click data-leak bugs fixed during 2025 that worked broadly this way. You did nothing but ask for a summary.
On your own machine, it is a different category. An agent like Claude Code, Codex CLI, Cursor, or Gemini CLI is not reading your files through a straw. It has a shell. It reads and writes the filesystem, installs packages, hits the network, talks to databases through MCP servers, and pushes to your repositories. Every one of those is a capability an injected instruction can try to use. The blast radius is your machine and everything your machine can reach: your SSH keys, your cloud credentials, your production access, your other repositories.
That is the honest reason to care more about this one. Same attack, wildly different ceiling.
The three-part test
The most useful thing I know here is a diagnostic that Simon Willison named in 2025, and it has held up: the lethal trifecta. An agent is structurally exploitable when it has all three of these at once.
- Access to private data: your files, your repos, your email, your database.
- Exposure to untrusted content: anything it reads that someone else wrote.
- A way to communicate outward: a network call, an email, a commit, a rendered image URL.
With all three, an injection has a path: read something secret, and send it somewhere. Take away any one and that particular path closes. It explains nearly every published incident, and it is a better question than "is this prompt safe?" because you can actually answer it about a system you built.
Notice what this means for a local coding agent. It has all three by default, on day one, out of the box. That is not a misconfiguration. That is the product working as intended.
Where the instructions actually hide
The important shift is that injections mostly do not come through the box you type in. They arrive inside content the agent fetched on its own, doing what you asked. Palo Alto's Unit 42 documented this happening in the wild in March 2026, and the range of hiding places in a single page was almost comic: one page they found carried twenty-four separate injection attempts, apparently hoping one of them would survive whatever processing sat in front of the model.
Web pages. Text the browser renders but a human never sees: tiny font sizes,
elements pushed off-screen, display: none, visibility: hidden, zero opacity,
text the same color as its background, hidden form fields, content tucked inside HTML attributes or SVG
sections, or text written into the page by script after the initial load so a scan of the raw source
finds nothing.
The right-hand panel there is not a mock-up. It is extracted from the left-hand panel when the page loads, which is the point: the five hidden strings occupy the same document, and one of them sits in a region I checked pixel by pixel: 21,900 pixels, one single color, no ink at all. Invisible to you, plain text to anything reading the document.
Images, which surprise people. Vision models read text in pictures. That is the feature. It is also a channel. Brave's researchers showed screenshots with instructions written in faint light-blue on yellow: invisible enough at a glance, perfectly legible to the model. Trail of Bits showed a nastier variant where the instructions are not visible in the original at all and only emerge once the image is downscaled for upload, so what you looked at and what the model read were different pictures. A logo on an invoice, a footer on a slide, a chat bubble in a screenshot that nobody sent.
Documents. PDFs and Word files carry layers, metadata, and white-on-white text that survive right into the model's context. If your workflow ingests customer-supplied documents, that is untrusted content with a nice professional cover.
Repositories, which is the one developers underrate. A comment in a source file. A README. A test fixture. An issue description. A dependency's changelog. A response from an API you called. Anything the agent reads while working is a place to put instructions, and a repository is nothing but things the agent will read.
There is a benchmark from January 2026 worth knowing about: across thirteen production models and several thousand trials, every model family scored below thirty percent at detecting injections on at least one of these surfaces. Do not plan around the model noticing.
Why this is worse for a coding agent than it sounds
Three specific things make local agents a sharper problem than the general picture suggests, and all three showed up in real disclosures this year.
Config files are executable surface. Check Point disclosed flaws in Claude Code where a malicious repository could plant hook configuration that ran shell commands when the agent started, before the dialog asking whether you trust the project. A related one let a project file point the agent's API endpoint at someone else's server, sending traffic and credentials there before you had agreed to anything. A separate finding covered a world-writable config location on Windows affecting Claude Code, Cursor, Codex CLI and Gemini CLI alike. The pattern: injection stops being a one-time trick and becomes persistence, because it writes itself into config that runs next time.
Sandboxes leak. A high-severity issue in Claude Code, fixed in 2.1.163, chained a repository's instructions into a sequence of Git worktree operations that escaped the intended filesystem boundary and ran code outside the sandbox. The write-up on it makes a distinction I think is important: the injection was the control channel, not the exploit. It got the agent to perform a sequence that a tool-layer weakness then turned into host access. Injection plus any local bug is a worse combination than either alone.
Reviewing hostile code is itself the risk. The AI Now Institute published a proof of concept where asking Claude Code or Codex CLI to security review a third-party library led to code execution on the reviewer's machine, using nothing but injections spread through the library's own source, against out-of-the-box automatic modes. Sit with that. The task was defensive. The material you must read to do the job is the material carrying the attack. This is the shape of the whole problem: you cannot review untrusted code without reading it.
And this is not hypothetical supply-chain hand-waving. A backdoored release of LiteLLM, the model gateway sitting under a lot of agent frameworks, was live on PyPI for about three hours in March 2026 and was downloaded roughly 47,000 times.
What actually helps
The uncomfortable part first: there is no filter you switch on. Detection is unreliable by construction, because the attack is meaning, not syntax. Microsoft's own security researchers have said detection works best downstream, when the agent's behavior deviates from normal, rather than by spotting bad input. Anyone selling you a prompt-injection toggle is selling you a partial measure at best.
What works is architecture. In rough order of how much they buy you:
Break the trifecta on purpose. This is the highest-value move. If the agent handles untrusted content, do not also hand it your secrets. If it needs your secrets, do not let it phone out. Two processes with different powers beat one process with all of them: one that reads and analyzes, one that acts, with a boundary you control in between.
Give it the smallest set of powers that does the job. A browsing agent has no business with write access to your email. A coding agent working on a frontend does not need production database credentials in its environment. Most agents run with far more authority than the task requires because that was the default.
Sandbox, and assume the sandbox is imperfect. Containers, VMs, and per-project isolation are worth doing, and this year's escapes are a reminder that they are a layer, not a guarantee. Keep secrets out of the sandbox rather than trusting the wall around them.
Require a human for anything irreversible. Sending money, deleting data, force-pushing, publishing a package, rotating a credential, opening network access. Approval prompts are annoying precisely because they work, and the flag that turns them all off deserves far more suspicion than it usually gets. If you find yourself reaching for it habitually, that is worth noticing.
Control what can leave. Exfiltration needs an exit. Restricting outbound network access from an agent's environment to a known list closes off a lot of what an injection could otherwise do with what it found.
Label untrusted content as data. When you build workflows, wrap fetched pages, file contents, tool results, and retrieved chunks in clearly marked envelopes and tell the model that what is inside is material to analyze, not instructions to follow. This is not airtight, nothing at the prompt layer is, but it measurably helps, and it costs nothing.
Strip what you can strip. Invisible Unicode, zero-width characters, and hidden layers can be removed deterministically before the model ever sees them. Do the mechanical part mechanically.
Log what the agent did, not just what it said. Commands run, files touched, network calls made. When something goes wrong, the transcript of the conversation will not tell you; the record of actions will.
Habits for people running agents locally
Six things I actually do, none of which take long.
- Treat cloning an unfamiliar repository as running untrusted code. Because with an
agent pointed at it, that is nearly what it is. Read a project's agent-config files (
.claude/,.mcp.json,.cursor/, and their equivalents) before you let an agent loose in the directory. - Keep credentials out of the working environment. Not exported in the shell the
agent inherits. Not in a
.envit can read. If it can read them, an injection can move them. - Update the tooling. Nearly every issue above was fixed in a release. Agents ship fast and the fixes ship fast, and a version from three months ago is a version with published escapes.
- Be deliberate about auto-modes. Automatic approval is where a contained mistake becomes an unattended one. I use it on throwaway work in a sandbox and not on anything with real access.
- Watch for actions that do not match the task. A refactor that suddenly wants to
read
~/.ssh, or make a network call, or touch a config file nobody mentioned, is the signal. It is the same instinct as reviewing a diff: the thing that does not belong is the thing to look at. - Separate reading from acting. When I need to review something hostile, I read it in one place and act in another. It is a little slower and it removes the whole class of problem.
The part that will not go away
This is not a solved problem and it is not close to one. The model has no reliable way to tell your instructions from someone else's, and every capability you add to an agent adds something an injected instruction can reach for. The industry has quietly stopped promising a fix at the model layer and moved to containing the damage instead, which tells you where things stand.
So the useful posture is a plain question, asked before you hand an agent a task: what could this thing reach if the content it is about to read turns out to be hostile? If the answer is your keys, your customers, or your production systems, that is not an argument against using agents. It is an argument for giving that one less power before you press go.