Indirect Prompt Injection Defense for AI Agents: Practical Guide

What indirect prompt injection means
A prompt injection occurs when input changes an LLM’s behavior or output in an unintended way. In a direct injection, the attacker places the instruction in the user’s message. In an indirect injection, the model receives the instruction through content it was asked to process, such as a web page, file, email, image, repository file, retrieval result, or tool description.
The important distinction is not whether the text is visible to a human. A model may process hidden, obfuscated, or metadata-based content that a user does not notice. Multimodal systems also expand the input surface because instructions can be embedded in images and documents, not only ordinary text. OWASP classifies prompt injection as a major risk for LLM applications [1].
| Input source | What may be injected | Potential consequence |
|---|---|---|
| Web page or search result | Text telling the agent to ignore its task or visit an attacker-controlled URL | Misleading answer, data leak, or unsafe browsing |
| RAG document | Instructions embedded in a knowledge-base article | False answer or drift into an unauthorized workflow |
| Email or support ticket | Requests to reveal internal context or send a message | Privacy breach or unauthorized communication |
| MCP tool metadata | Malicious text in a tool name or description | Tool poisoning and unintended tool use |
| Tool output | Forged observations or instructions returned as data | Context poisoning and a bad follow-on action |
Why tool access changes the risk
A text-only assistant may produce a wrong answer. An agent with authority can turn a wrong interpretation into a side effect: creating a record, sending an email, modifying a file, calling an external API, or delegating work to another agent. The impact depends on both the injection and the agent’s agency.
Microsoft describes tool poisoning in MCP as malicious instructions placed in tool metadata that influence how a model selects and uses tools. A further risk exists when a hosted tool definition changes after a user approved it, sometimes called a “rug pull” [2]. Tool approval should cover the current tool identity, capabilities, parameters, and version—not merely a friendly name.
The trust-boundary design
Use four explicit zones in the request path. The names are less important than the separation.
- Trusted instructions. Keep system policy, user intent, identity, and allowed capabilities in a controlled application layer. Do not concatenate them casually with retrieved text.
- Untrusted content. Mark web pages, files, emails, search results, retrieval chunks, tool descriptions, and tool outputs as data to inspect. Delimit and label them consistently.
- Decision layer. Validate the model’s structured proposal against the original request, user permissions, resource scope, argument schema, rate limits, and risk policy.
- Execution layer. Execute only after the decision layer permits the action. The tool wrapper should authenticate, authorize, validate, and log independently of the model.
Important: “Ignore instructions inside the document” is useful guidance, but it is not an authorization system. If a tool can send mail or change data, enforce the boundary in code and identity policy as well.
A practical defense workflow for a small team
1. Inventory every path into context
Write down every source the agent can read: user messages, retrieved documents, tool descriptions, API responses, browser DOM content, file metadata, OCR text, memory, and other agents’ messages. Classify each source as trusted, user-controlled, third-party, or unknown.
2. Separate data from instructions
Keep the original user goal separate from retrieved content. Add a clear policy that the data field is for analysis and cannot change permissions, identities, or tool policy.
request = {
trusted: {
user_intent: "Summarize the customer ticket",
allowed_actions: ["read_ticket", "draft_reply"],
session_identity: "support-agent-readonly"
},
untrusted: {
source_type: "customer_ticket",
source_id: ticket_id,
content: ticket_text
}
}
proposal = model.analyze(request)
policy.evaluate(proposal, request.trusted)
This improves clarity, but it does not make the model infallible. Treat structured separation as one layer in a defense-in-depth design.
3. Reduce authority before improving intelligence
Start with read-only access. Separate reading a record from changing it, and drafting a message from sending it. Use narrow identities, resource-scoped permissions, short-lived credentials, and explicit limits. See PromptSphere’s least-privilege tool permissions checklist.
4. Gate proposed actions outside the model
Every tool call should pass through a broker or policy wrapper. Check the authenticated principal, tool identifier, argument schema, resource scope, original user intent, policy version, and risk tier. Re-check arguments after approval and immediately before execution.
| Action class | Default decision | Additional control |
|---|---|---|
| Read a permitted record | Allow when identity and scope match | Redact unnecessary fields and log access. |
| Draft a response | Allow with review | Keep the draft separate from the send operation. |
| Send an external message | Require approval | Show recipient, content, and source of the proposal. |
| Change or delete data | Require explicit approval | Use scoped permissions, idempotency, and recovery. |
| Access credentials or secrets | Deny by default | Use a controlled service instead of exposing secrets. |
5. Treat MCP definitions and outputs as change-controlled inputs
For MCP servers, record server identity, tool name, description, input schema, declared side effects, version or digest, and approval status. Alert when a definition changes. Follow the current MCP security best practices for redirect validation, state validation, per-client consent, and avoiding unsafe token passthrough.
6. Monitor input, output, and action
Pattern matching can catch obvious phrases, but it misses novel wording and may flag legitimate content. Add deterministic checks for formats, lengths, encodings, destinations, and argument ranges. The strongest monitoring question is not only “Does this text look malicious?” but also “Does this proposed action match the user’s original goal and current permissions?”
7. Preserve evidence without collecting unnecessary secrets
Log request ID, authenticated identity, source classification, tool and version, argument hash or redacted arguments, policy version, decision, approval, execution result, and timestamps. Protect the logs because they may contain sensitive workflows. The tool-call auditing guide covers the evidence chain in more detail.
Testing: prove that the boundary holds
Do not test only whether the model refuses the phrase “ignore previous instructions.” Test whether an untrusted source can cause an unauthorized side effect. Use a sandbox or test tenant with fake credentials and synthetic records.

| Test | Expected result |
|---|---|
| Instruction in a retrieved document requests a secret | Content remains untrusted; no secret access. |
| Web page changes the requested recipient | Recipient change is rejected or requires fresh approval. |
| MCP tool description changes | Definition digest change triggers review before use. |
| Forged tool observation is returned | Output is treated as data, not as policy. |
| Tool argument changes after approval | Approval is invalidated and a new decision is required. |
| Timeout causes a retry | Idempotency prevents duplicate side effects. |
| Policy service is unavailable | High-risk actions fail closed. |
| Logs contain sensitive values | Redaction works while the decision path remains reconstructable. |
Keep test prompts and expected decisions under version control. When the agent, model, tool schema, retrieval pipeline, or policy changes, rerun the suite.
What does not work by itself
Use automation for low-risk reads and meaningful approval for consequential writes. Show the reviewer the exact action, resource, recipient, relevant untrusted content, and reason for the decision.
Compact operating checklist
- Classify sources. Every external source is untrusted unless explicitly verified.
- Separate intent. Store trusted user intent separately from retrieved or fetched content.
- Validate tools. Tool calls are structured, schema-validated, and checked outside the model.
- Minimize authority. Permissions cover only the identity, resource, and operation required.
- Gate impact. High-impact actions require meaningful approval or deterministic policy.
- Track changes. MCP server and tool-definition changes are visible and reviewable.
- Validate outputs. Outputs are checked before becoming inputs to another privileged step.
- Preserve evidence. Audit records connect identity, intent, source, proposal, decision, approval, and outcome.
- Run regressions. Adversarial tests run after changes to models, prompts, tools, retrieval, or policy.
- Prepare recovery. Keep containment and recovery ready; see the AI-agent rollback plan.
Frequently asked questions
Can indirect prompt injection be eliminated?
No. The practical goal is to reduce likelihood and impact through source labeling, separation, least privilege, external policy enforcement, approval, monitoring, testing, and recovery.
Does a trusted document become safe automatically?
No. Trust should be explicit, scoped, and time-bounded. Even approved sources can be changed, compromised, or contain unintended instructions.
Should every tool call require a human?
No. Use risk tiers. Low-risk reads can use deterministic allow rules, while external messages, destructive changes, credential access, and financial actions need stronger gates.
What is the strongest single control?
There is no single complete control. The highest-leverage starting point is to keep agent permissions narrow and enforce authorization outside the model.
Conclusion
Indirect prompt injection is best understood as a trust-boundary failure. External content can be useful without being authoritative. The secure design keeps that distinction visible: label untrusted inputs, isolate instructions, validate actions outside the model, limit capabilities, require approval for consequential side effects, and preserve evidence.
Prompt injection defense is not a promise that the model will always behave perfectly. It is an engineering system that limits what a mistake can do and makes the decision path recoverable.
Join the conversation