LLM Security: Prompt Injection, the Attacks, and What Defending Actually Costs
Here’s the uncomfortable thing about building with LLMs. The moment your model reads anything it didn’t get directly from your user, a retrieved document, a web page, an email, a PDF, a calendar invite, that text can contain instructions. And the model, by default, can’t tell the difference between “content it should summarize” and “commands it should obey.” To an LLM, it’s all just tokens in the prompt.
That’s prompt injection, and it sits at number one on the OWASP Top 10 for LLM Applications for a good reason: it’s easy to do, hard to fully stop, and it gets worse the more capable and connected your system becomes. An agent with tools and access to private data is exactly the thing an attacker wants to hijack.
This post walks the real attack types with harmless examples, the defenses that address each, and then the question I get asked last but that you should ask first: what does defending actually cost you in latency, extra model calls, and money? Because some of these defenses are free and some triple your per-request cost, and knowing which is which is half the job.
Two flavors of injection, and the nasty one
The textbook attack is direct injection: the user themselves types something to override your instructions. Annoying, but the user is attacking their own session. The one that should worry you is indirect injection, where the malicious instructions are hidden in content the model reads on someone else’s behalf.
Direct injection
The user types instructions that fight your system prompt. They're attacking their own session, so the blast radius is usually themselves.
Indirect injection (the dangerous one)
The instructions hide inside content the model reads: a document, an email, a web page. The user never sees them. The model treats them as commands.
Here’s why indirect injection is the one that turns into a breach. It reaches an agent through the exact pipeline that makes agents useful: the agent pulls in untrusted content, that content carries a hidden instruction, and the agent then acts on it with the tools and access it holds.
Simon Willison, who named prompt injection in the first place, has a sharp way to describe when this gets truly dangerous. He calls it the lethal trifecta: an agent is exposed when it has all three of these at once.
All three together = exfiltration risk. Remove any one and the attack path breaks.
That framing is genuinely useful for design: if you can’t make an agent safe, at least don’t give one agent all three legs of the trifecta at once.
The rest of the attack surface
Injection is the headline, but OWASP’s list covers the whole surface, and the others matter just as much once you’re in production. Here’s the landscape, each in a line.
A couple worth dwelling on, because they’re the ones teams forget. Improper output handling is just old-school injection with an AI in the middle: if your model writes SQL and you run it raw, a poisoned prompt gets you a dropped table. Treat model output like any other untrusted user input. And excessive agency is the multiplier: an injection that can only make the model talk is embarrassing; an injection that can make it call send_email or delete_file is a breach. The fix is boring and architectural: give the agent the fewest tools, narrowest scopes, and least autonomy the job allows.
Now the real question: what does defending cost?
This is where most security write-ups go quiet, and it’s the part you actually budget around. Defenses split cleanly into two camps: the ones that are basically free, and the ones that add a whole extra model call (or several) to every request. Let me put the cost right up front.
To make the “extra call” part concrete: an unprotected request is one model call. Wrap it in input and output screening and you’ve potentially tripled that.
So the answer to “will this add latency and extra LLM calls?” is: the cheap defenses don’t, and the strong ones do. Here’s the full picture in one table.
| Defense | What it stops | Extra call? | Latency | Cost |
|---|---|---|---|---|
| Delimiters / spotlighting | Injection (marks data as data) | No | Negligible | Free |
| Instruction hierarchy | Injection (priority baked in) | No | None | Free |
| Output encoding / validation | Improper output handling | No | Sub-ms | Free |
| Least-privilege tools + HITL | Excessive agency | No | Human approval only | Free |
| Structured output / allow-lists | Malformed / unexpected actions | No | Negligible | Free |
| Moderation / content filter | Harmful content, some jailbreaks | Yes (cheap) | +1 round-trip | Low |
| Guardrail classifier (in + out) | Injection, jailbreaks | Yes, per screen | +1 per screen | Per call |
| Dual-LLM (privileged/quarantined) | The lethal trifecta | Yes, multiple | Highest | Highest |
The defenses, briefly, cheap ones first
Spotlighting and delimiters (free). Wrap untrusted content in randomized markers and tell the model everything inside is data, not instructions. Microsoft’s spotlighting work reports this cutting indirect-injection success from over half to under a few percent on common models, for the price of a few extra tokens. It’s the first thing to reach for because it costs nothing.
Instruction hierarchy (free). Newer models are trained to rank instructions: system prompt beats user, user beats content the model merely read. It’s built into the model, so it adds nothing at inference. Lean on it, but don’t assume it’s absolute.
Treat output as untrusted (free). For improper output handling, this is pure appsec: parameterized queries instead of string-built SQL, escape anything going into HTML, never eval model output, validate tool arguments against an allow-list before running them. Deterministic code, no model call, done.
Least privilege and human-in-the-loop (free on the model budget). The best defense against excessive agency isn’t clever, it’s stingy. Fewest tools, narrowest scopes, and a human approval gate on anything irreversible. The only “cost” is a person clicking approve on high-impact actions, which you want anyway.
Guardrail classifiers (this is the paid tier). A separate model screens inputs and outputs for attacks. AWS Bedrock Guardrails, Azure Prompt Shields, and Google Model Armor all do this. They catch what the free defenses miss, and they’re vendor-managed and updatable. The catch, and it’s the honest one: the guardrail model can itself be injected, so it’s defense-in-depth, not a wall. And it costs one extra call per screen, which is where your latency and bill grow.
Dual-LLM (the expensive, strong pattern). Willison’s design splits the work: a privileged model holds the tools but never sees untrusted content, and a quarantined model reads untrusted content but has no tools. A controller passes only references between them, never raw tainted text. It genuinely breaks the injection path, and it costs you multiple model calls and real orchestration complexity. Worth it when you’re staring down the full lethal trifecta and can’t remove a leg.
So what do you actually turn on?
Start with everything free, because it’s free and it covers a surprising amount: spotlight untrusted content, lean on instruction hierarchy, treat all output as untrusted, and starve your agents of unnecessary tools and permissions. That baseline stops a lot and costs you nothing but discipline.
Then spend on the paid tier where the risk earns it. A public-facing agent that reads untrusted web content and holds real tools? Yes, put a guardrail classifier in front and behind it, and eat the extra calls. An internal tool over trusted data with a human in the loop? You probably don’t need to triple your per-request cost to feel safe.
The mistake is treating security as a single switch you flip, usually the expensive one, and calling it done. It’s layers, and the cheap layers do more of the work than people expect. Add the costly ones deliberately, where an attacker actually has a path and something to steal.
Because the real lesson of prompt injection is humbling: you cannot make the model perfectly distinguish data from instructions. So you stop trying to win that fight inside the prompt, and you win it around the prompt instead, with least privilege, untrusted-output handling, and, where it counts, an architecture that breaks the path between reading something bad and doing something bad.
Related: the agent design post covers the least-privilege and human-in-the-loop side in depth, and streaming context into agents is exactly the “agent reads untrusted events” surface this attacks.
References
Written from scratch. These are the primary, verified sources behind the attacks, defenses, and cost claims. All examples above are harmless and illustrative. Nothing here is copied from these.
- OWASP Top 10 for LLM Applications 2025: https://genai.owasp.org/resource/owasp-top-10-for-llm-applications-2025/
- OWASP LLM01: Prompt Injection: https://genai.owasp.org/llmrisk/llm01-prompt-injection/
- OWASP LLM Prompt Injection Prevention Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/LLM_Prompt_Injection_Prevention_Cheat_Sheet.html
- Simon Willison, the lethal trifecta for AI agents: https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/
- Simon Willison, the dual-LLM pattern: https://simonwillison.net/2023/Apr/25/dual-llm-pattern/
- Simon Willison, design patterns for securing LLM agents: https://simonwillison.net/2025/Jun/13/prompt-injection-design-patterns/
- Simon Willison on OpenAI’s instruction hierarchy: https://simonwillison.net/2024/Apr/23/the-instruction-hierarchy/
- Microsoft, defending against indirect prompt injection (spotlighting, Prompt Shields): https://www.microsoft.com/en-us/msrc/blog/2025/07/how-microsoft-defends-against-indirect-prompt-injection-attacks
- Microsoft spotlighting paper: https://arxiv.org/pdf/2403.14720
- Anthropic, many-shot jailbreaking: https://www.anthropic.com/research/many-shot-jailbreaking
- AWS Bedrock Guardrails, detect prompt attacks: https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-prompt-attack.html
- Azure AI Content Safety, Prompt Shields: https://learn.microsoft.com/en-us/azure/ai-services/content-safety/concepts/jailbreak-detection
- Google Cloud Model Armor: https://cloud.google.com/security/products/model-armor
- NIST AI 100-2, adversarial machine learning taxonomy: https://csrc.nist.gov/news/2025/nist-ai-100-2-adversarial-machine-learning-taxonom