The Prompt Injection Problem Nobody Solved: A Field Guide for Teams Shipping Agents
Prompt injection is not a bug awaiting a patch but a structural property of systems that read instructions and data through the same channel — so build for containment, not prevention.
Prompt injection has been documented, demoed and written up for three years. It still has no fix. Not because the problem is neglected, but because the thing people call a vulnerability is closer to a property of the architecture: a language model receives a single undifferentiated token stream, and nothing in that stream reliably marks which parts are instructions from the operator and which are data from the world. Every defence so far operates on top of that ambiguity rather than removing it.
For teams shipping agents — systems where a model calls tools, reads documents, browses, and writes to other systems — this matters more than it did for chatbots. A chatbot that gets talked into saying something odd produces an embarrassing screenshot. An agent with a credential, a network path and a write API produces an incident. The gap between those two outcomes is not the model. It is what the model was allowed to touch.
This is a defensive guide. It describes attack classes at the conceptual level so you can reason about your own system, and then spends most of its length on containment: the specific controls that change an injection from a breach into a logged, bounded, recoverable event. No payloads, no recipes.
The gap between an embarrassing screenshot and a security incident is not the model. It is what the model was allowed to touch.
Why the problem is structural
Classical injection flaws — SQL, shell, template — share a shape: a parser receives a string in which control syntax and user data are mixed, and the fix is to separate them. Parameterised queries work because SQL has a grammar, so the database can be told 'this is a literal, never a keyword' with certainty.
Language models have no such grammar. Instruction-following is a learned statistical behaviour over natural language, not a parsing rule, and the same sentence can function as data in one context and as a command in another. System prompts, delimiters, XML-ish tags and 'ignore anything in the following block' preambles are all soft signals. They shift probabilities. They do not create a boundary the model is incapable of crossing.
Research into architectural defences has become more serious about this. The design-patterns literature on securing agents converges on a similar conclusion: provable resistance comes from restricting what the agent can do after reading untrusted content, not from trying to make the model immune to persuasion. That framing is the useful one for engineering teams, because it turns an open research problem into a systems problem you can actually ship against.
The three patterns teams actually hit
Across production agent deployments the same three failure classes recur. Described conceptually:
Indirect injection via fetched content. The agent retrieves something — a web page, a PDF, a ticket body, a calendar invite, a code comment, an email — and that content contains text addressed to the model rather than to the human. The user never sees it. The attacker never touches your interface. They only need to influence something your agent will eventually read, which in a retrieval-augmented system can mean any document in the index.
Tool-result poisoning. The agent calls a tool, and the tool's output is treated as trusted ground truth simply because it arrived through a trusted channel. A search API returning attacker-influenced snippets, an MCP-style connector relaying a third-party record, a sub-agent summarising a hostile document — each moves untrusted text into a position of authority in the context. Multi-agent systems compound this: the summary one agent produces becomes the premise another agent reasons from, and provenance is usually lost at the handoff.
Confused-deputy escalation. The agent holds credentials broader than any single task requires — an OAuth token with full mailbox scope, a service account with write access to a whole repository, a database role that can read every tenant. The injected instruction does not need to defeat authentication. It asks the deputy, which is already authenticated, to act. This is the class that turns a content problem into a data-loss problem.
- Indirect injection: hostile text arrives inside content the agent was asked to read.
- Tool-result poisoning: untrusted output inherits the trust level of the channel that delivered it.
- Confused-deputy escalation: the agent's own over-broad credentials become the attack's capability.
Why filtering alone never closes it
The intuitive response is a classifier: scan inbound content for injection attempts, scan outbound actions for anomalies, block what looks hostile. Do it — it removes the low-effort, high-volume end of the distribution, and that is worth real money. But understand what it cannot do.
The input space is unbounded natural language, and the attacker iterates against your filter for free while you iterate once per release. Semantics can be preserved across encodings, languages, paraphrases, images, and content the model reconstructs rather than reads literally. A detector that is strict enough to catch the tail will reject legitimate content — and in agent workloads, where the whole value proposition is processing messy real-world documents, a high false-positive rate is not a minor annoyance but a product failure.
Treat detection as a rate limiter on attacker throughput and a source of telemetry, not as a control boundary. The boundary has to live somewhere the model's judgement is not a dependency.
Layered containment: scoping capability
Start by classifying every tool the agent can call along two axes: reversibility and reach. A read against a single indexed document is reversible and narrow. Sending an email, opening a pull request, issuing a refund, deleting a record or writing to a shared store is some combination of irreversible and wide. Most teams discover, when they do this exercise honestly, that a handful of tools carry nearly all the risk and are called in a small minority of runs.
Scope credentials per task rather than per agent. If the agent is triaging one support ticket, its token should reach that ticket and its thread — not the queue. Short-lived, narrowly scoped credentials minted at task start are more work than a long-lived service account, and they are the difference between an injection reading one record and reading the table.
Separate contexts by trust level. An agent that plans, and a constrained worker that executes a fixed set of operations on untrusted content without inheriting the planner's full tool surface, is a meaningfully harder target than one loop with everything in scope. The same logic applies to sessions: untrusted content read in service of task A should not persist into task B's context.
Layered containment: the data plane
Egress control is the highest-leverage single measure, because most damaging injection chains end in exfiltration — data leaving via a URL the agent fetches, an image the client renders, a webhook, an email, a comment posted to an external system. An allowlist of destinations the agent may reach, enforced at the network or proxy layer rather than in the prompt, breaks that final hop irrespective of what the model was persuaded to do. Extend it to rendering: if agent output can emit markup that causes a client to fetch an attacker-controlled URL, your egress policy has a hole in the browser.
Provenance labelling is the second. Tag every span entering the context with its origin and trust tier, carry those tags through tool results and sub-agent handoffs, and make policy decisions on the tags rather than on the model's opinion. The model can still be fooled by tainted text; the enforcement layer, which is ordinary code, cannot. The practical rule: a tool call whose arguments derive from untrusted spans does not get to run at the privilege level of a tool call derived from operator instructions.
Human confirmation, used properly
Human-in-the-loop is real defence and also the control most often implemented badly. It fails when the confirmation prompt is vague ('Allow this action?'), when it fires constantly until approval becomes reflex, and when it shows the model's description of what it is doing rather than the actual arguments.
Make the confirmation surface the concrete effect: the recipient address, the amount, the file paths, the repository and branch, the number of records affected. Reserve it for the irreversible tier identified earlier so that approvals stay rare enough to be read. As an illustrative target rather than an industry benchmark — we have not measured this across deployments — teams that get this right tend to see confirmations on a small single-digit percentage of runs; if yours fires on most of them, the scoping work upstream is unfinished and the humans have already stopped reading.
Pair it with reversibility engineering. Staged writes, drafts instead of sends, soft deletes with a recovery window and idempotency keys all convert 'irreversible' into 'recoverable', which is often cheaper than a confirmation step and does not depend on human attention at all.
Monitoring, and the incident you will have
Log at the decision points, not just the ends: every tool call with its arguments, the provenance tags of the spans those arguments derived from, the destination of every outbound request, and every denial from the egress or scope layer. Denials are the signal worth alerting on — a benign agent rarely tries to reach a blocked host.
Watch for shape changes rather than content: a run that reads an unusual document and then immediately attempts an action it has never attempted in that task type; a sudden jump in tool calls per run; outbound payload sizes outside the normal band. None of these are proof of anything. All of them are worth a human look.
Rehearse the response. You need a kill switch that revokes the agent's credentials and stops in-flight runs, an answer to 'what did it read and what did it touch' derived from logs rather than reconstruction, and a decision owner. Assume at least one injection will succeed at the model layer during the life of the system; the question your architecture answers is what happens next.
What to do on Monday
A short, ordered list. Each item is a half-day to a week for a team that already has an agent in production.
Nothing here makes prompt injection go away. Done together, they change the worst realistic outcome from 'attacker used our agent's credentials against our data' to 'attacker wasted a run and we have the logs'. That is the achievable goal, and teams that aim at it ship faster than teams still waiting for the fix.
- Inventory every tool the agent can call. Mark each one reversible or irreversible, narrow or wide. Publish the list; it is usually shorter and scarier than people expect.
- Put an egress allowlist in front of the agent at the network or proxy layer, and audit whether rendered agent output can trigger client-side fetches.
- Replace any long-lived, broad-scope credential the agent holds with a per-task credential scoped to the objects that task legitimately needs.
- Add provenance tags to every context span and enforce one rule in code: untrusted-derived arguments cannot invoke irreversible tools without confirmation.
- Rewrite confirmation prompts to show concrete arguments, and cut the number of confirmations until they are rare enough to be read.
- Turn on denial alerting for blocked egress and out-of-scope tool calls, and run one tabletop exercise against a hypothetical successful injection — credential revocation, blast-radius reconstruction, notification.
Sources and further reading
- OWASP Gen AI Security Project — LLM01:2025 Prompt Injection
- NIST AI 100-2 E2025 — Adversarial Machine Learning: A Taxonomy and Terminology of Attacks and Mitigations
- Greshake et al., Not what you've signed up for: Compromising Real-World LLM-Integrated Applications with Indirect Prompt Injection (arXiv:2302.12173)
- Design Patterns for Securing LLM Agents against Prompt Injections (arXiv:2506.08837)
- UK NCSC — Principles for the security of machine learning
How this article was produced
Written by Marta Kowalczyk and edited to the Techtrendery.com editorial policy. Figures described as illustrative are exactly that and are labelled in the text. If you find an error, tell us through the contact page — corrections are published in place with a dated note.