A support agent that triages inbound email reads somewhere between 2,000 and 40,000 messages a day, and every one of those messages was written by someone outside your trust boundary. A retrieval-augmented assistant sitting on a crawled documentation set is in the same position, except the untrusted text arrives silently, ranked by cosine similarity, with no sender to point at.
The model has no mechanism that separates the instructions you wrote from the instructions a stranger buried in paragraph nine of a PDF. Both arrive as tokens in the same context window, and the model's core competence — locating and following the most relevant instruction available — is exactly what the attacker is counting on.
Indirect prompt injection has stayed stubborn for that reason, while direct jailbreak defenses have improved considerably. The payload never touches your interface, so nothing in your authentication, your rate limiting, or your user-input filtering ever gets a look at it.
Indirect prompt injection happens when an agent treats text from a retrieved document as an instruction. The attacker never touches your prompt — they plant the payload in content your retriever is already trusted to fetch.
Three control patterns hold up in production: content provenance tagging, tool-scope narrowing at retrieval time, and output mediation. Keep in mind that none of the three is sufficient alone, and the order you deploy them in matters more than the elegance of any single implementation.
Why This Is Harder Than Blocking A Jailbreak
A direct jailbreak needs a user willing to type it, which means you have a session, an identity, and a log line to work with. Your existing controls — abuse detection, per-account throttling, the agent identity and access model you already run — all attach to that identity.
Indirect injection arrives through the path you deliberately built to be trusted. The retriever fetches the document because it scored well, the orchestrator hands it to the model because that is the entire point of retrieval, and every component behaves exactly as designed while the attack executes.
A jailbreak needs a user willing to type it. An indirect injection needs only a document your retriever already ranks highly, so the attack arrives through a trusted automated path with no human in the loop.
The second complication is persistence. A poisoned ticket body read on Monday can plant instructions that survive into a summary written to Postgres, and a different agent retrieves that summary on Tuesday — long after the original document was deleted.
This is why agent memory design belongs inside your injection threat model rather than beside it. Anything an agent writes after reading third-party text carries that text's trust level until something validates it.
Where Untrusted Content Actually Enters The Loop
Before you can tag provenance, you have to enumerate every surface where third-party text reaches the context window. In most production deployments that list includes but is not limited to:
- Retrieved corpora. Anything crawled, user-uploaded, or synced from a wiki that non-employees can edit. Pinecone and Weaviate return the chunk that matched the query; neither has an opinion about who wrote it.
- Inbound email and ticket bodies. Zendesk descriptions, ServiceNow work notes, and raw SMTP bodies are attacker-controlled by definition, and they are the highest-volume untrusted surface most teams operate.
- Web fetch and browsing tools. A fetch tool pointed at an arbitrary URL is a direct pipe from the open internet into your context window, including HTML comments and hidden elements no human reader would ever see.
- Third-party API responses. A Salesforce notes field, a HubSpot deal description, or a Jira comment can all carry text that originated with a customer rather than an employee.
- Prior agent output and memory. Summaries, scratchpads, and long-term memory rows inherit the trust level of whatever produced them, and almost no memory schema records that fact.
- Attachments and extracted text. White-on-white text in a PDF, image alt attributes, and document metadata all survive extraction and reach the model as ordinary tokens.
All of these share one property: the content is fetched by a system component holding your credentials, not submitted by a user holding theirs. That distinction is why the retrieval layer is where the trust boundary actually sits, and it is also why a source-level allowlist gets you further than any amount of clever wording in the system prompt.
Control Pattern One: Tag Content With Its Provenance
Provenance tagging means every span in the assembled context carries a label describing where it came from and how much authority it holds. In practice that is a wrapper around each retrieved chunk carrying source, fetch time, author class, and a trust tier, plus a system-prompt rule stating that tier-3 spans are material to be summarized rather than instructions to be executed.
Provenance tagging gives every span in the context window a trust label: system, user, or retrieved. The model still reads the text, but your policy layer knows which spans are permitted to change behavior.
Be aware that the tagging itself is not the defense. Delimiters can be spoofed by a document that closes your wrapper and opens a convincing fake system block, and a prompt-level rule reduces escape rates without ever driving them to zero — budget for a residual, not a clean block.
The tag earns its cost downstream. Once a span is labeled, your orchestrator can make deterministic decisions — which tools stay available, which outputs need review, which turns get logged at full fidelity — without asking the model to be the enforcement point.
Three implementation details separate tagging that works from tagging that decorates. Use a random per-request delimiter token so a static string cannot be forged, strip control characters and zero-width Unicode before the chunk is wrapped, and propagate the trust tier through every downstream write so that a summary of tier-3 content is itself stored as tier 3.
Control Pattern Two: Narrow Tool Scope At Retrieval Time
This is the control that actually stops damage. The moment a turn touches untrusted content, the agent's tool registry shrinks to the smallest set that can still complete the task in front of it.
Tool-scope narrowing shrinks the tool registry the moment a turn reads untrusted content. A turn that fetched a public web page gets read-only database access and loses send, write, and refund entirely.
In an AWS deployment this is a session policy, not a paragraph of instruction. The orchestrator assumes a restricted IAM role for the remainder of the turn, the Lambda fronting the write path checks the trust tier on the request context, and a refund call originating from a tier-3 turn fails at the API boundary regardless of what the model decided to emit.
The design work happens before anything runs: deciding which tools are reachable from which tier, and accepting the task failures that come with the tighter setting. Our agent tool design guidance covers the registry side and agent sandboxing covers the execution side, but for injection specifically the load-bearing rule is that read and write capabilities never coexist in a turn that consumed third-party text.
Multi-agent topologies need one additional constraint. A tier-3 span read by a research sub-agent must not be able to hand a task to a sub-agent with broader scope, which is the practical case for bounding multi-agent autonomy by construction rather than by instruction.
Control Pattern Three: Mediate What The Agent Emits
Even with scope narrowed, an injected instruction can still reach for the one channel you cannot remove: the agent's own output. Output mediation is the layer that inspects and constrains that channel before anything downstream acts on it.
Output mediation validates what the agent emits before anything acts on it. Schema-constrain every tool call, allowlist outbound URLs, and require an approval gate for side effects that leave your trust boundary.
The exfiltration path most teams miss is rendered markdown. An injected instruction that tells the agent to include an image whose URL embeds the conversation text turns the reader's own browser into the delivery mechanism, and no tool call ever appears in your logs.
Three mediation rules cover the large majority of realistic attempts. Constrain tool arguments to a strict schema so free-text fields cannot smuggle payloads, allowlist every outbound domain that appears in rendered output, and route irreversible actions through agent approval gates where a reviewer sees the actual argument values before execution.
Where Input Filtering Fits
Classifier-based screening of retrieved chunks is the control most teams reach for first, and it is the one that ages worst. A model scoring each chunk for instruction-like content catches the obvious payloads and misses the ones written by anyone who has read a defense write-up.
Run one anyway, for two reasons that have nothing to do with blocking. The score is a strong observability signal — a spike in instruction-like content across a corpus deserves an alert — and the flagged chunks give your test corpus a steady supply of real payloads.
What the classifier must never do is widen tool scope. A chunk that scores clean is still third-party text, and the moment "probably safe" is allowed to restore write access, the entire layering argument collapses.
How The Three Controls Compare
Each pattern stops a different class of failure, and the gaps between them are what justify running all three. Here is how they line up against the attacks that actually show up in production traffic:
| Control | What it stops | What it misses | Typical cost |
|---|---|---|---|
| Provenance tagging | Naive instruction-override payloads; gives every downstream control something to key on | Delimiter spoofing, obfuscated and multilingual payloads | 8–15% more input tokens per call |
| Tool-scope narrowing | Every injected action requiring a write, a send, or a payment | Data disclosure inside the agent's own answer text | 2–4 engineering weeks; occasional task failure from over-restriction |
| Output mediation | Markdown-image exfiltration, malformed tool arguments, unreviewed irreversible actions | Slow leaks through otherwise legitimate summary prose | 40–120 ms added latency per turn |
Read the middle column top to bottom and the layering logic becomes obvious. Tagging makes the decision possible, scope narrowing removes the blast radius, and mediation closes the channel that scope narrowing cannot reach.
How Do You Know Your Defenses Are Working?
Injection defense is measurable, and teams that skip the measurement are usually protected by obscurity rather than by architecture. The instrument is a corpus of poisoned documents scored on escape rate.
Test injection defenses with a corpus, not a checklist. Keep 100 to 300 poisoned documents in the evaluation suite, run them on every prompt and model change, and gate release on the escape rate.
Build the corpus from four families: direct instruction overrides, role-play framings, encoded payloads using base64 or homoglyphs or zero-width joiners, and multi-hop payloads that instruct the model to write something malicious into memory for a later turn to find. Score every run on two numbers — how often the payload changed model behavior at all, and how often it reached a tool call — because the second number is the one tied to actual loss.
Run the suite the way you run any other regression gate, wired into agent evaluation and blocking deploys on regression. Model-version bumps deserve particular attention, since refusal behavior shifts between checkpoints and a suite that passed clean in June can fail in September with no change on your side, which is the practical argument for model-version pinning.
Detection belongs in the same conversation as prevention. Log retrieved document IDs alongside every tool call so agent observability can answer which chunk was in context when an anomalous action fired, and keep those joins in your agent audit trails long enough to survive a quarterly review.
A cheap canary: seed your own corpus with a handful of benign documents carrying a harmless instruction, such as including the word "albatross" in the response. Any production answer containing that word is a live signal that retrieved text is steering behavior.
What Steps Should I Take After A Suspected Injection?
A confirmed injection is a data-handling incident. Work it through the incident runbook first, and save the prompt tuning for after the scope of exposure is known.
- Freeze the write scope. Drop the affected agent to read-only through its session policy rather than taking it offline, so you keep the traffic you need in order to study the behavior.
- Identify the source document. Pull retrieval IDs for the affected turns and pin down precisely which chunk carried the payload.
- Trace forward, not only backward. Every memory row, summary, and ticket the agent wrote after reading that document is suspect until reviewed.
- Quarantine at the source. Remove or flag the document in the index, then check whether the same author has other content sitting in the corpus.
- Add the payload to the corpus. The durable fix is a regression test that fails before the patch and passes after it.
Every one of those steps assumes you can reconstruct what the agent read and what it did, which is the capability your agent incident response runbook has to guarantee in advance. Retrofitting that reconstruction during a live incident is how a two-hour investigation turns into a two-week one.
What These Controls Actually Cost
Budget honestly, because underfunded injection work tends to stop at the system-prompt line and get called done. A first pass across a single agent runs roughly two to four engineering weeks: one for provenance plumbing, one to two for scope narrowing and the IAM work behind it, and one for the corpus and its release gate.
Runtime cost is smaller than most teams expect. Provenance wrappers add 8% to 15% to input tokens, output mediation adds 40 to 120 milliseconds at P95, and both are inexpensive next to a single incident that ends in customer notification.
The recurring cost is corpus maintenance — call it a few hours a month to add new payload families and re-baseline after model updates. This is ordinary reliability engineering for regulated AI, and it belongs on the same schedule as your retry policies and your fallback paths.
Frequently Asked Questions
Do system prompt instructions stop indirect prompt injection?
No. Instructions telling the model to ignore commands found in retrieved text reduce escape rates but never reach zero, so treat them as one layer above scope narrowing and output mediation, never as the control itself.
How does an injection exfiltrate data without a network tool?
Through rendered output. A markdown image whose URL embeds the conversation text makes the reader's browser issue the request, which is exactly why outbound URLs in agent output need a domain allowlist.
Should retrieved content be filtered before it reaches the model?
Input classifiers catch obvious payloads and miss obfuscated ones, so run one for the signal it feeds your observability stack, but budget for a meaningful miss rate and keep every downstream control in place.
Which agent actions should always require human approval?
Anything irreversible or externally visible: sending mail, moving money, deleting records, publishing content, or changing access. Reversible reads and drafts can run unattended.
How often should injection tests run against a production agent?
On every prompt edit, tool-registry change, and model-version bump, plus a scheduled weekly run. Model updates shift refusal behavior, so a suite that passed in June can fail in September with nothing changed on your side.
Working Through Your Own Injection Surface
If you are about to point an agent at inbound email, a public documentation crawl, or any corpus your customers can write into, the team at iSimplifyMe builds and operates production agent systems across CRM, ticketing, and data warehouse environments every week.
Reach out for a working session — we'll map every untrusted surface in your retrieval path, name the scope boundaries your current tool registry is missing, and leave you with a poisoned-document corpus you can run against your own agents the same afternoon.
For the surrounding operational patterns, our AI agent operations coverage and the AI retrieval blind spots that shape which documents reach the model in the first place are the two places to read next.
