Skip to content

Prompt Injection: The Vulnerability With No Clean Fix

5 min read · updated August 3, 2026

A vulnerability with a name this tidy usually has a patch. This one does not, and the reason is worth understanding before you evaluate a single mitigation: the model reads instructions and data on the same channel, and no amount of filtering creates a channel that is not there.

One channel, two kinds of content

A language model takes a sequence of tokens and returns a distribution over the next one. Everything an application assembles — the system prompt, the user’s message, a retrieved document, the output of a tool call, the contents of a web page the agent fetched — is flattened into that one sequence before the model sees any of it.

Roles are part of that flattening, not an exception to it. A chat template marks turns with special tokens and the model has been trained to weight them, which is real and useful, but it is a learned preference rather than an enforced boundary. Nothing in the runtime prevents a token in the middle of a retrieved document from being read the way a token in the system prompt is read. There is no privileged register, no out-of-band control path, and no parameterisation.

That gives the vulnerability its one-line definition: text that arrives as data and is acted on as instruction. OWASP tracks it as LLM01 in the OWASP Top 10 for LLM Applications, and notably does not claim a complete mitigation for it — the guidance is about constraining privilege and behaviour, not about detection.

Why this is not a filtering problem

A filter needs a decidable predicate: given this string, is it an instruction? That predicate does not exist. Consider what a filter would have to get right at once:

  • Instructions are not syntactically distinctive. “Please summarise the attached invoice” is an instruction. So is the sentence you just read. An imperative mood is not required, a second language is allowed, and the same meaning survives paraphrase indefinitely.
  • Legitimate data contains instructions. An email your agent is summarising says “forward this to accounting”. A support ticket says “close as duplicate”. The agent must read those as content, not obey them — and the difference is not in the text. It is in where the text came from, which the model cannot see.
  • The attacker gets unlimited attempts. A classifier in front of the model is itself a model with a false-negative rate. Anyone who can submit content can probe it repeatedly and offline. You need it to be right every time; they need one.
  • The payload need not be legible. Instructions survive encoding, unusual scripts, whitespace tricks, being split across two documents that are retrieved together, and being carried in fields nobody thinks of as text — a filename, an image caption, a code comment, a calendar invite’s location field.

None of this makes input filtering worthless. It makes it a rate reducer rather than a boundary, and the distinction decides whether you are allowed to put a dangerous capability behind it.

The SQL injection analogy, and where it breaks

Everyone reaches for SQL injection, and the analogy is instructive right up to the point where it fails. SQL injection was solved — not mitigated, solved — by parameterised queries. The fix separates the query from the values so the database parses your syntax and never parses theirs. The channel was split, in the protocol, permanently.

There is no equivalent split available for a model. Its only input is one sequence, and its “parser” is a learned function whose behaviour on unseen text cannot be enumerated. The closest analogue available in a prompt is delimiters — wrapping untrusted content in markers and telling the model to treat what is inside as data. That is escaping, and escaping was never the recommended fix even for SQL, for the same reason it is weak here: it depends on the parser honouring a convention that the attacker is also allowed to write.

Random per-request delimiters are better than fixed ones, because the attacker cannot guess the closing marker. They are still a heuristic layered on a model’s cooperation, not a boundary the system enforces.

What actually follows from this

If the hole cannot be closed at the input, the design question changes from “how do I stop the injection?” to “what happens when one succeeds?” Four consequences do most of the work:

  • Model output is untrusted input. Anything the model emits may have been authored by whoever controlled the content it read. If that output reaches a shell, a SQL string, an HTML render, an eval, or a tool argument, you have a second injection downstream. OWASP calls this LLM05, Improper Output Handling, and it is where most exploitable damage actually lands.
  • Blast radius is set by privilege, not by words. A successfully injected model that can only return text is a correctness bug. The same injection in a model holding a database credential and an outbound HTTP tool is a breach. Nothing about the injection changed; the capability list did.
  • Policy belongs in code, not in the prompt. “Never reveal customer records” in a system prompt is a request. The same rule enforced in the tool layer — the query is scoped to the authenticated tenant before it runs — is a control. Anything you would be unwilling to see bypassed should not live in prose.
  • Residual risk is expected, so make it survivable. Design as though some fraction of injections succeed, because they will. That means reversibility, audit logs, spend limits, and a human on irreversible actions.

A defensible posture

The posture that holds up under review is unglamorous and it is mostly about privilege. Give the model the smallest set of tools that does the job. Scope every credential to the acting user, at the point of use, server-side. Separate the context that reads untrusted content from the context that is allowed to act. Require confirmation on anything you could not undo in an afternoon. Log every tool call with its arguments and its result, because you will need to reconstruct a session that went wrong.

Then add the detection layers — classifiers, delimiters, output scans — knowing what they are: they lower the frequency of a successful attack and they are not the reason the system is safe. The lethal trifecta gives you a single design rule to apply the whole posture with, and the defence inventory grades the individual controls.

Prompt Injection: The Vulnerability With No Clean Fix · Multigrid