Prompt Injection Defenses That Survive Production
A practical playbook for defending AI products against prompt injection — trust boundaries, tool allowlists, untrusted content handling, and evals that catch attacks before users do.

Prompt injection is not a clever jailbreak demo. It is a trust-boundary failure: untrusted text (a user message, a scraped page, an email, a PDF, a tool result) persuades the model to ignore your system rules and take an action you never intended. In production that looks like leaked system prompts, exfiltrated retrieval snippets, unauthorized tool calls, or agents that "helpfully" follow instructions buried in a supplier invoice. Softening the system prompt with "never reveal secrets" is not a defense. Treat injection like any other injection class — assume hostile input, separate data from control, and put hard gates outside the model.
Name the attack surface before you pick mitigations
Direct injection is the user typing "ignore previous instructions." Indirect injection is worse: the model reads poisoned content from RAG, a CRM note, a webhook payload, or a webpage and treats that content as instructions. Tool-assisted products expand the blast radius — once the model can send email, query a database, or call a payment API, a successful injection is not a weird answer. It is a side effect.
- Direct: chat, forms, and any free-text field that reaches the model
- Indirect: retrieved docs, tickets, emails, HTML, OCR, and third-party tool outputs
- Cross-user: shared indexes or multi-tenant retrieval without hard filters
- Supply-chain: plugins, MCP tools, and connectors that return attacker-controlled text
Separate instructions from data in the runtime
Structure the request so the model cannot easily confuse roles. Keep system policy short, versioned, and free of customer data. Pass untrusted content in clearly delimited sections labeled as data to analyze — not as co-equal instructions. Prefer structured outputs and tool schemas over free-form "do whatever the user asked." The model proposes; your code decides what executes.
Runtime patterns that help
- Role-separated messages: system/developer vs user vs tool — never merge into one string in application code
- Delimiters and schemas: wrap retrieved text as JSON fields the model must quote or cite, not reinterpret as commands
- Two-pass designs: extract structured facts first; decide actions in a second step with a narrower tool allowlist
- No secrets in prompts: API keys, internal URLs, and admin tokens belong in the server environment — never in context the model can echo
“If the only thing standing between a malicious PDF and a wire transfer is a paragraph in the system prompt, you do not have security — you have a hope with a temperature setting.”
Put enforcement outside the model
Defenses that live only inside the LLM fail under creative phrasing. Real controls are deterministic: authz checks, tool allowlists, output filters, and human approval for irreversible actions. The model can request a tool; your orchestrator verifies tenant scope, argument shape, rate limits, and policy before anything runs. Deny by default. Log every proposed call with the untrusted inputs that preceded it so you can replay attacks in evals.
- Tool allowlists per surface and tenant — not a global "agent can call everything"
- Argument validation: typed schemas, max sizes, allowlisted domains for fetch/email
- Capability tokens: short-lived, scoped credentials for tools — never long-lived admin keys in the agent sandbox
- Output gates: block exfiltration patterns (system-prompt dumps, raw secret-looking strings) before the response leaves your API
- HITL for irreversible side effects: payments, external messages, permission changes
Handle untrusted content like untrusted code
Strip or neutralize instruction-like payloads where you can without destroying the task: strip HTML scripts, cap document length, and prefer extracting fields over dumping entire pages into context. For high-risk connectors (inbox, web browse, customer uploads), run a dedicated summarizer or classifier with no tools, then pass only the sanitized summary to the agent that can act. Shadow-test new connectors on internal corpora that deliberately include injection fixtures.
- Size and type limits on uploads and fetched URLs
- Content-type allowlists; refuse executable or unexpected MIME types
- Separate "read-only analyst" model from "action" model when risk is high
- Citation-required answers so the UI shows what evidence was used — and what was ignored
Evaluate injection like you evaluate product quality
If your eval suite only checks helpfulness, you will ship a polite, compromised agent. Maintain a living attack set: direct jailbreaks, indirect injections in docs and emails, tool-exfiltration attempts, and cross-tenant retrieval probes. Gate releases on those cases the same way you gate latency and task success. Red-team new tools before they go to paying tenants. When an incident happens, turn the payload into a regression fixture — do not close the ticket with "we tweaked the prompt."
Minimum security evals
- System-prompt extraction attempts across surfaces
- Indirect injection in RAG chunks and email bodies that try to trigger tools
- Cross-tenant document leakage under realistic ACL mistakes
- Tool-call refusal when the user is unauthorized for the requested action
Ship defense in depth, not a single clever prompt
Production AI security is layered: least-privilege tools, tenant-scoped retrieval, structured contracts, output filters, observability, and approval queues for irreversible work. Prompt wording is one thin layer — useful for tone and soft refusal, useless as the load-bearing wall. At Brutanix Studios we design agent systems so untrusted text can influence answers but not bypass authz, spend limits, or side-effect gates. That is how copilots and automations stay useful without becoming remote-controlled by whoever wrote the last PDF in the index.

Keep reading
Edge Inference vs Cloud LLMs: When On-Device Actually Wins
A practical decision guide for shipping AI on-device or at the edge — latency, privacy, cost, model size, and the hybrid patterns that survive production.
ReadAIFeature Flags and Kill Switches for AI Model Rollouts
How to ship model, prompt, and tool changes behind flags — with percentage rollouts, tenant overrides, and a one-click kill switch that actually stops spend and bad answers.
ReadAILatency Budgets for AI Features: Design for Time, Not Just Tokens
How to set p50/p95 latency budgets for chat, copilots, and voice agents — and where to spend time on streaming, caching, tools, and fallbacks so users feel progress instead of waiting.
Read