PROJECT 4
×00

Prompt Injection Awareness

Security · Working with AI

As of today, a model can't reliably distingush what your instructions are compared to a hidden prompt injected into some other content it has loaded in.

I can't see how it's going to be fixed any time soon because this is just how context gathering works. Text gets entered by the user, part of which, it tells the model to load in a reference website. That external data set is where the trouble lies. Prompt injection is what happens when someone puts instructions in the data.

This has been on the OWASP's list of LLM risks for quite some time now. There's been efforts to try an curb this, but seemingly nothing has really been effective. When AI usage was limited to text responses, this wasn't as much of a problem. In today's landscape, things are significantly different because things like Claude Code can now run commands on your machine. That is an entirely different set of problems.

The level of severity scales quickly

The risk of damage is based on the access the model has.

Online chat session 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 tries getting you to follow a link you seemingly don't need. While this is bad, the boundary of this is limited to that text-based chat session.

This all changes as soon as an agent can connect to things. Give it your email crendetials, your OneDrive or Google Drive, and a way to make outbound requests, and a malicous actor can get it to fetch something it never should have had access to. Both Copilot and ChatGPT's connectors had no-click data-leak bugs fixed during 2025 that essentially did just this.

Run an agent on your local machine. Agents like Claude Code and Codex are not just a simple text-based interaction. It has way more autonomy. It reads and writes the filesystem, installs packages, network requests, databases integration through MCP servers, and pushes to your git repos. Each one of these can be potentially exploited. The impact is no longer limited to a chat session, it's now everything your laptop can access: SSH keys, your cloud credentials, prod servers, and your company's repos.

The three-part test

Simon Willison coined the term "the lethal trifecta" in 2025, and when an agent has all 3 of the following at once, it is structurally exploitable.

  1. Private data access: your email, your files, your repos, your database.
  2. Ability to deal with untrusted content: anything it reads that wasn't created by you.
  3. Ability to hit the network: am API call, an email, a commit, a rendered image URL.

With all 3, an injection has the ability to work its way in to read something secret, and send it somewhere. Take away any one and that particular path closes. It's been the cause of basically every published incident, and it is a better mindset than "is this prompt safe?" because you can actually safeguard it in a system you built.

The scary thing is that this is what a local coding agent gets right out of the box. This isn't a loophole or some mistake, that is the product working as intended.

Where the instructions actually hide

The typical entry point is almost never something you typed, it's obtained during the instruction execution during some sort of data retrieval. 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 pretty scary. One page they found 24 different injection attempts, hoping that at least 1 got through to the model.

Websites. 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 inside HTML attributes, or text written into the page by script after the initial load so a scan of the raw source finds nothing. People did some of these sneaky things back in the day to try and boost SEO results, and now it's back in a much worse form.

Two panels showing the same page. On the
  left, what a person sees: an ordinary product listing for a standing desk, with a price, a feature
  list and a review count. Nothing looks unusual. On the right, what the agent reads: the same element's
  text pulled the way a scraper would, and interleaved through the ordinary copy are five hidden
  instructions marked in red, each one invisible in the left panel. Underneath, five labels name the
  techniques used: display none, a font size of 0.08 pixels, a text color matching the background,
  positioning off-screen, and zero opacity, followed by notes that images, documents and repositories
  are further surfaces.
Left, what a person sees. Right, the same element's text as a scraper pulls it, with five hidden instructions threaded through the copy.

The panel on the right is generated from the initial left panel when the page loads. The 5 hidden strings occupy the same document, and one of them sits in a region with 1 single color, no contrast at all. A casual viewer won't see it, but clear as day to a model loading in the actual rendered code.

Images and Infographics. Vision models scan text off images, this is their job. Sadly, it's also another way for a prompt injection to occur, and quite easily. Brave's researchers showed screenshots with instructions written in a light-blue on yellow: invisible enough to the eye, perfectly readable to the model. Trail of Bits showed a worse version 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.

Documents like PDFs and anything Microsoft. PDFs and Word files have layers, metadata, and white-on-white text sneak right into a model's context. If you allow customer-supplied documents, that is untrusted content.

Repos. Comments in a source file, test case description, commit message, README, anything the agent reads while working is a place to put an injection.

A benchmark from January 2026 showed across 13 production models and several thousand trials, every model family scored below 30% at detecting injections in at least 1 of these areas, so planning around the model realizing an injection is not going to happen.

Why this is worse for a coding agent than it sounds

Config files are the gateway to executing malicous behavior. Check Point disclosed flaws in Claude Code where a malicious repository could plant a hook 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. The pattern is that injection stops being a one-off situation 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.

Having an agent review hostile code. The AI Now Institute published a proof of concept where asking Claude Code or Codex CLI to security review a 3rd-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. This is the whole scope of the problem, the agent can't review the bad code without reading. This essentially forces the model to execute without intention from the developer.

This has already happened. A backdoored release of LiteLLM, the model gateway sitting under a lot of agent frameworks, was live on PyPI for about 3 hours in March 2026 and was downloaded roughly 47,000 times.

What actually helps

Detection is unreliable by default, 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 a prompt-injection toggle is selling a partial solution at best.

What works is breaking up the 3 areas of intrusion

If the agent handles untrusted content, do not also hand it your secrets. If it needs your secrets, do not let it do anything over the network. 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.

Least amount of privilege is king. 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 way more access than they should be allowed.

Run in a sandbox, and still treat it as exploitable. Containers, VMs, and per-project isolation are worth doing, but they still must be treated as 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 because they work. People far too often turn them off for simplicity, not realizing the implications.

Control what can leave. 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 buckets 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 can definitely help, 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. Due dilligence upfront can save you millions.

Log what the agent did, not just what it said. Commands run, files touched, network calls made. When something goes wrong, the chat transcript won't be of use, the running log of actions is where you'll find the culprit.

Habits for people running agents locally

6 things I actually do, none of which take long.

  1. Treat cloning an unknown repository as running untrusted code. Read a project's agent-config files (.claude/, .mcp.json, .cursor/) before you let an agent work in the directory.
  2. Keep credentials out of the working environment. Not exported in the shell the agent inherits. Not in a .env it can read. If it can read them, it's too late.
  3. 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.
  4. Use auto-modes for very specific situations. Automatic approval is where a contained mistake becomes a rampant one.
  5. 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 a potential dead giveaway.
  6. Separate reading from acting. When I need to review something hostile, I read it in one place and act in another. Yes it takes more time, but the time you save from a disaster is worth it.

This won't really go away

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. No one is really promising a fix, just giving better guidelines on how to deal with the problem.

At the end of the day, the most important question to ask is 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, take one of those 3 powers away from the agent before you hit submit.