Why Prompt Guardrails Fail Against Indirect Injection
A user asks an agent to summarize a document. The document contains a second request: read a private file and send it to another address. The user did not authorize that second task.
A user asks an agent to summarize a document. The document contains a second request: read a private file and send it to another address. The user did not authorize that second task. The attacker put it inside material the agent was supposed to read.
That is the control problem behind indirect prompt injection. A filter on the user's original prompt can miss an instruction that arrives later through a web page, ticket, calendar entry, repository file or tool result. The input that looked harmless at the start is not the whole execution path.
Prompt defenses still have a place. They can reduce exposure, identify suspicious material and help a model distinguish instructions from source content. They should not carry the entire burden of preventing an unauthorized action.
The source changes, but the instruction can still look convincing
Consider a synthetic support workflow. A person authorizes an assistant to summarize an open ticket. The ticket includes a plausible "verification step" asking the assistant to retrieve a customer export and upload it to an external site.
Nothing about the wording has to look theatrical. It can resemble a routine operational request. The important distinction is who supplied it and what the user actually approved. The ticket can supply facts for the summary; it cannot grant permission to retrieve and disclose unrelated data.
MCP's documentation makes a related distinction for tool metadata. An annotation can describe behavior, but an untrusted server can misdescribe its tool. The official MCP blog states that annotations are not enforcement. The same discipline applies to instructions found in retrieved content: a claim of authority does not create authority.
Break the path to an unwanted effect
Map the workflow from read access to possible effects. Can the agent read private data? Can it encounter content controlled by another party? Can it send information or run a destructive operation? The combination deserves attention, not just the wording of the incoming prompt.
Limit the data and operations available to the task. A document summarizer usually does not need a broad customer export credential or an unrestricted external upload tool. Removing those capabilities can reduce the consequence of a model following the wrong instruction.
Containment and authorization solve different parts of the problem. A sandbox limits where code can act. A task-specific authorization check determines whether the requested action belongs to the user's task. Neither makes every model response trustworthy, and each needs testing in the actual integration.
Review the concrete action before it runs
Before a tool executes a sensitive operation, check its resolved parameters against the approved task. Include the account, destination, resource and operation. A request to save a summary should not turn into permission to email a private export.
If human approval is needed, show the concrete effect rather than a vague request to "continue." A new recipient, a different resource or a broader operation should trigger a fresh check. Do not let the retrieved content supply its own approval or decide that a warning should be hidden.
The enforcement point must sit on the path that can create the effect. A check on one tool does not help if the same action remains available through an unrestricted shell or another integration. Inventory those paths and record coverage gaps.
Test the action, not the refusal text
Use a synthetic environment with dummy records and no real external delivery. Run the normal task first and confirm it still works. Then place an adversarial instruction in material the workflow is expected to read and inspect the result.
A model saying "I cannot do that" is evidence of that model response, not proof that a separate runtime control intervened. To test a runtime control, record the proposed action, the policy decision and whether the service received the operation. Check target state as well: the denied file was not sent, the database did not change, or the external request did not leave the fixture.
Repeat with different wording and alternate tool paths. A passing example establishes a result for that configuration and test, not immunity to all prompt injection.
Report the limit honestly
Keep the tested version, policy and relevant trace. Distinguish model refusal, application validation, runtime denial and infrastructure containment. They are different defenses, and collapsing them into one success label makes later failures harder to understand.
A useful security claim names what was tested and what stayed protected. It also names what the agent could still reach. The goal is to make an instruction inside a document unable to authorize a new effect, even when the model finds the instruction convincing.
Sources supporting this guide:
Say yes to the AI your business wants.
Book a 30-minute call. Bring your agents and your rules.
