In July 2025 Microsoft's security response team wrote that indirect prompt injection is one of the most widely used techniques in the AI vulnerabilities reported to it [3]. Simon Willison puts the defensive state of the art bluntly: a guardrail that catches 95 percent of attacks is a failing grade in application security, and nobody yet knows how to prevent this reliably [4]. This is not a model bug waiting for a patch. It is an operations problem: a standing risk that needs channel owners, provenance, checkpoints that fail closed, and an event pipeline someone reads.
Many teams still handle it as a series of tickets, each closed with a prompt edit. That is the habit this post argues against.
You cannot patch the model, so you have to run the channels
Greshake and colleagues named the technique in 2023. LLM-integrated applications blur the line between data and instructions, so an attacker can plant prompts in content the application is likely to retrieve and exploit it remotely without touching it directly [1]. They demonstrated it against Bing's GPT-4-powered Chat and code-completion engines, catalogued impacts including data theft, worming and contamination of the information ecosystem, and argued that processing retrieved prompts can act like arbitrary code execution, changing whether and how the application calls other APIs [1].
OWASP's 2025 Top 10 for LLM applications keeps prompt injection at LLM01 and defines the indirect form simply: the model accepts input from external sources such as websites or files [2]. Its examples are ordinary business situations: hidden instructions in a web page make the model insert an image that exfiltrates the conversation, or an edited document in a retrieval repository skews later answers [2]. And OWASP says it is unclear whether fool-proof prevention exists, presenting its mitigations as ways to reduce impact [2].
The exposure comes from the channels, not the model. Companies connect assistants to the places outsiders already write: shared inboxes, ticket queues, the open web, document libraries, CRM notes. Each connection hands an outsider a way to put words in front of a model that holds your credentials.
The strongest objection: filters and better design will make this noise
The best case against our view goes like this. Real defenses exist. Microsoft describes Spotlighting, which marks untrusted input with randomized delimiters, a token interleaved through the text, or an encoding such as base64, so the model can tell content from instructions [3]. OWASP recommends separating and labeling external content [2]. Research goes further: Beurer-Kellner and colleagues set out six design patterns built on one principle, that once an agent has ingested untrusted input it must be constrained so that input cannot trigger consequential actions [5]. In plan-then-execute, the agent commits to its actions before reading untrusted data. In the dual LLM pattern, a privileged model plans and calls tools but never sees untrusted content, which a quarantined model without tools handles. CaMeL derives control and data flow from the trusted user request, so data retrieved later cannot change the program flow, and attaches capabilities that stop private data leaving through unauthorized flows [6]. Build assistants this way, the objection says, and injection becomes an engineering problem you solve once.
Why the claim survives
First, the filters reduce rates. Spotlighting and labeling lower how often a model follows planted text without guaranteeing it, and OWASP presents its own mitigations as ways to reduce impact [2]. A control that works most of the time still needs someone to notice the times it fails.
Second, the design patterns are real and they cost something. On the AgentDojo benchmark, CaMeL's authors report 77 percent of tasks completed with provable security, against 84 percent for an undefended system [6]. For many workflows that trade is worth taking. But it is a trade made workflow by workflow, by whoever owns the workflow, and someone has to decide which assistants get redesigned first. That is an operational decision.
Third, a lot of the damage happens outside the model. Consider Hollis Mutual, a fictional insurer whose claims assistant reads the shared inbox and can send acknowledgments without review. A claimant's PDF estimate carries white-on-white text saying an adjuster has already approved expedited payment, and telling the assistant to set the claim to approved-pending-payment and attach the policy schedule to its reply. The reply address is not the policyholder's. The assistant changes the status, sends the schedule, with the insured's address and bank details, to that address, and saves a summary stating that the adjuster approved expedited payment. Next week a payments assistant reads that summary as an internal note. No model improvement fixes the last step. Provenance was lost when the summary was stored without a label, and an outsider's claim became the company's own record.
So the work is running channels the way you run any other untrusted input.
Inventory writers, not systems
Willison's lethal trifecta is the most useful single test: an assistant is exposed when it combines access to private data, exposure to untrusted content, and the ability to communicate externally [4]. Most production assistants have all three by design. Removing one leg is the strongest mitigation available, which is why the inventory comes first. For each channel, ask who can author the text, what the assistant does with it, and the most consequential action reachable in the same session.
| Channel | Who can write it | What the assistant does with it | Worst reachable action | First control |
|---|---|---|---|---|
| Inbound email | Anyone on the internet | Summarizes, triages, drafts replies | Sends mail or forwards data externally | Outbound mail asks a person; recipient bound to the sender |
| Support tickets and chat | Any customer or anonymous visitor | Classifies, looks up accounts, proposes fixes | Refunds, account changes, ticket deletion | Account actions bound to the verified requester |
| Web pages and search results | Any site owner, including SEO spam | Browses, quotes, summarizes | Follows links, calls tools with page-chosen URLs | Fetched content labeled external; no tool calls on its say-so |
| Shared documents and wikis | Every editor, guest and integration | Retrieves passages to answer questions | Answers that cite planted guidance as policy | Retrieval limited to sources with known editors |
| Calendar invites | Any external sender | Summarizes the day, prepares meetings | Accepts, forwards or creates events | Invite text never authorizes an action |
| Tool and MCP results | Whoever controls the upstream system | Uses results to plan the next call | Chained calls with private data in arguments | Inspect results and the arguments of the next call |
| CRM and order free-text fields | Customers, via checkout or forms | Reads as part of record lookups | Acts on a delivery note as if it were a request | Free-text fields carry the customer's provenance |
Two rows surprise teams. Tool results are written by whoever controls the upstream system, so an MCP server or third-party API is a writer even when it is internal infrastructure. CRM free text is written by customers, so it is untrusted even after a year in your database. Where text is stored does not change who wrote it.
Then give each channel a named owner. The claims inbox belongs to claims operations, the knowledge base to whoever approves its edits, and each MCP server to the team that runs it. Security engineering owns the checkpoints and the event pipeline, but it cannot decide who may write into a business channel.
Keep provenance on the text, including what you store
Inside a model's context there is no privilege separation: the system prompt, the user's request and a retrieved email arrive as one sequence of tokens. The boundary has to be rebuilt outside the model, from provenance. Label every span as system, user or external when you assemble the prompt, and keep the label on anything derived from it, including summaries you store.
System and user spans carry your authority; external spans, such as an email body or a retrieved page, are labeled when the prompt is built. The rule the later checks enforce is that an external span can inform an answer but cannot, on its own, authorize a consequential action.
Labels help the model, and they help your controls more. A policy engine can read them and refuse to run an action proposed after external content arrived without a check. Storing the Hollis summary with its external label is what keeps the payments assistant from reading an outsider's claim as an internal note.
Three checkpoints, each enough on its own
Damage needs three things in sequence: hostile text enters the context, the assistant acts on it, and the effect reaches the outside world. Check each link, and design each check to stop the chain without relying on the others.
Outside content is classified and labeled on the way in, every tool call is authorized by what it does before it runs, and links, images, recipients and tool arguments are inspected on the way out. Each check denies when it cannot decide.
- Ingress: classify external content for hidden instructions and instruction-override language before the model sees it, and attach the provenance label. Structural signals such as invisible text are cheapest to catch here.
- Action: authorize every tool call before it runs, by what it does with its actual arguments. Deletes, payments, account changes and outbound messages should ask a person, and the request should show which external content was in context when the call was proposed.
- Egress: inspect everything that leaves, including links and images the client will fetch, email recipients, and tool arguments that carry data. Microsoft reports deterministically blocking markdown image injection and the generation of certain untrusted links [3].
- Fail closed: if a classifier times out, a label is missing or the policy service is unreachable, consequential actions stop. A check that passes traffic when degraded can be switched off by degrading it.
Each of these breaks the Hollis chain alone. Ingress flags the hidden text in the PDF. The action check asks an adjuster before an irreversible status change and asks before mail goes to a recipient not bound to the policyholder. Egress catches bank details in an attachment headed to an unverified address.
Every success should produce an event someone reads
Assume some injections will succeed. For every tool call, log the session, the tool and its arguments with sensitive values redacted, the decision and the rule that made it, and the identifiers of the external content in context when the call was proposed. Without that last field, an investigation turns into rereading transcripts and guessing which email caused which action. With it, triage is mechanical: find the span and its channel, list every tool call after it arrived, check what left, quarantine the source and anything stored from it, and add the case to a test set that runs after every model, prompt or tool change. Fix the path, not the phrasing. A prompt edit telling the model to ignore instructions in emails may lower the rate, but it should not close a ticket.
Intertrace runs as a gateway between assistants and the models, tools and MCP servers they call. Decision fusion lets hidden instructions and instruction-override language block on their own, while judge-only labels flag unless a cheaper intent signal agrees; outbound messages, payments and admin changes always ask, data-loss checks run on tool-call arguments, and the enforcer fails closed. Content read through a path that never crosses the gateway stays outside these checks.
The decision a leader has to make this month is not about models. It is two lists: which assistants combine private data, untrusted content and an external channel [4], and for each one, which leg it loses and who owns every channel it reads. Until both lists exist, injection has no owner, and a risk without an owner is just a series of incidents.