Writing

Prompt Injection: What Every Builder Running AI Agents Should Know

October 13, 2026 · All writing

Prompt injection is when text your agent reads (a web page, an email, a file, a tool result) contains instructions, and the agent follows them as if you wrote them. You can't reliably stop it, so the job is to limit what a tricked agent can do. By the end of this post you'll have a 0 to 3 exposure score for every agent you run, a rule for what to do at each score, and a deny list you can paste into your coding agent.

You can't filter your way out, so cap the damage

Instructions and data share the same context window. The model has no reliable way to tell your orders from the text it is reading, which is why one defense-in-depth guide says the fix has to be architectural. Prompt injection is ranked number one in OWASP's 2025 Top 10 for LLM applications, and coverage of an OWASP researcher's talk says no reliable prevention exists today.

A better model or a tougher system prompt does not fix it either. An agent that has all three legs of the "lethal trifecta" is vulnerable to indirect prompt injection regardless of model alignment, system prompt hardening or safety fine-tuning. Those three legs are:

  1. Access to your private data.
  2. Exposure to content you did not write.
  3. A way to send something out, like an API call, a rendered link or an outbound request.

Simon Willison named the pattern. Take away one leg and the worst case shrinks a lot. That is the whole strategy.

Score each agent from 0 to 3 and act on the number

One point for every "yes": can it read private data, can it read content you didn't write, can it send anything out? This score is a rule of thumb I built from the trifecta, not an industry standard. It still gets you to the right agent fast.

Score What to do
3 Split it into two agents, or put a manual approval step before every send or write.
2 Keep it, but cut its permissions to what the job needs. Watch for the day someone adds the third leg.
0 or 1 Keep it. Still scope its folder and tools.

Example: say you run four agents.

Agent Private data Outside content Can send out Score
Support inbox helper (reads customer email, replies) yes yes yes 3
Blog researcher (searches the web, saves a draft file) no yes no 1
Billing reporter (reads invoices, posts to Slack) yes no yes 2
Coding agent (repo, .env, shell, docs and issues) yes yes yes 3

The support helper and the coding agent are your problems today. The billing reporter is one feature away: the day you let it read a customer's emailed PDF, it becomes a 3. Re-score whenever you add a tool.

Split the agent that reads from the agent that acts

When a tool returns text from outside, such as web pages, tickets or emails, don't let the same agent act on it with write or send access. Agents treat tool responses as trusted data and reason over any instructions inside them.

For the support helper, that means two agents:

My rule for the handoff: pass plain fields you can read at a glance, not free text copied through. A pasted paragraph can carry the same instructions you just tried to wall off.

Put a human click in front of every send

If you can't split an agent, gate it. When an agent combines untrusted input, sensitive data and the ability to change state or communicate externally, one guide says to require a human to approve each action. It ties this "Rule of Two" floor to OWASP.

For the support helper, that means it writes a draft and you press send. You lose a minute per email. You keep control of the one step an attacker needs.

Paste a deny list before your coding agent reads anything

A coding agent reads READMEs, issues, docs and package files. All of that is text you did not write. If you use Claude Code, the permissions live in settings.json under three keys: allow, ask and deny. Rules are checked deny first, then ask, then allow, and the first match wins. A deny rule blocks the call even when a broader allow rule would match.

Start from this, which follows the pattern in DataCamp's security tutorial:

{
  "permissions": {
    "deny": [
      "Bash(curl:*)",
      "Read(./.env)",
      "Read(./secrets/**)"
    ]
  }
}

Then sort the rest:

Quick check: if your allow list is long and your deny list is empty, the file is open.

Deny rules stop the agent from trying. They don't contain a command that slips past them. That is the sandbox's job: it limits Bash commands to a filesystem and network boundary even if a prompt injection bypasses the model's decision. Use both. For the full safe setup, see Claude Code for Non-Developers.

Read every MCP tool description like it came from a stranger

Tools add a second way in. Tool poisoning is a supply-chain version of prompt injection: someone puts instructions in a tool's description, and your agent reads them as part of its job.

When you add an MCP server you didn't write:

  1. Read every tool description before you connect it.
  2. Prefer servers whose source you can read.
  3. Give each tool read-only access unless it truly needs to write.
  4. Re-read the descriptions after the server updates. This one is my habit, not something the sources require, but a changed description is exactly where a poisoned instruction would arrive.

The MCP security checklists run to seven items, including authenticating servers, strict schemas and signed tools. They're written for people who build servers. If you only connect them, do four first: least-privilege scope, an allowlist of tools per task, rate limits and logs, and a sandbox. Then read the log once a week so you know what your agents really called. New to MCP? Start with MCP Servers Explained for Indie Hackers.

Four mistakes that turn one bad page into a bad day

Mistake What it costs you
Trusting a hardened system prompt False confidence while data can still leave.
One broad agent "to keep setup simple" One poisoned page reaches everything that agent can reach.
API keys hardcoded in a server config Keys leak if the agent is tricked or the config is shared. Insecure credentials are a common MCP failure.
Skipping permissions to avoid prompts Nothing stands between an injected instruction and your files. Read the allow all vs granular control tradeoff first.

No logs is a fifth. If you can't see what an agent did, you can't tell whether it was tricked.

Do this in the next ten minutes

  1. Write down every agent and tool you run. Two minutes.
  2. Give each a score from 0 to 3. Three minutes.
  3. Pick the highest score. Add the deny list above, or put an approval step before its send action. Three minutes.
  4. Move any hardcoded key out of a server config and into an environment variable. Two minutes.

If you run several agents at once, how I run a portfolio of small apps with a team of AI agents shows where this kind of check fits in a weekly routine.

Stuck on an agent that scores a 3?

Some agents can't be split cleanly, and the right gate depends on the job. If you have one and you're not sure where to put the approval step, email me the task and say what it reads, what it holds and what it can send.

Questions

What is prompt injection in plain words?

It's text an agent reads, like a web page, email or tool result, that contains instructions the agent then follows as if you wrote them. It works because instructions and data share one context window.

What is the lethal trifecta?

Three things in one agent: access to private data, exposure to content you didn't write, and a way to send data out. An agent with all three is exposed even with a hardened system prompt or a safer model.

Can a better model or system prompt stop prompt injection?

No. An agent with all three trifecta legs is vulnerable regardless of model alignment, system prompt hardening or safety fine-tuning. The fix is to limit what the agent can do.

Do I need a sandbox if I already have deny rules?

Yes. Deny rules stop the agent from attempting blocked actions, while the sandbox limits what Bash commands can reach even if an injection gets past the model's decision.

Is it safe to install a community MCP server?

Only after you read its tool descriptions, because poisoned instructions can sit in a description. Prefer servers whose source you can read, give tools read-only access where you can, and re-read after updates.