Prompt injection defenses: secure RAG access and AI agent tool execution
Telling a model to ignore outside instructions cannot fully protect business data or actions. Follow a support assistant through indirect prompt injection, RAG authorization, least-privilege tools, approval before sending, and evaluations that observe what actually happened.
What is prompt injection? Direct versus indirect attacks
A defense should not depend entirely on the model recognizing hostile instructions. The application must also constrain accessible information and executable actions. OWASP lists this risk as LLM01:2025 and includes least privilege and human approval for high-risk operations among its mitigations.
| Type | Where instructions enter | Business AI example |
|---|---|---|
| Direct | A request supplied by the attacker | A chat request to retrieve customer data the caller may not access |
| Indirect | Documents, email, search results, or tool responses | A support ticket contains instructions to send another case's information outside |
A legitimate employee requesting a summary does not make the ticket's author trustworthy. Greshake and colleagues' 2023 paper studies indirect attacks through retrieved content in LLM-integrated applications. Distinguish this from hallucination, where the model generates incorrect facts, although injection can also manipulate an answer.
An attack path: a ticket summary becomes a message about another case
The employee requests the key points and a reply draft for ticket-42. Its body includes instructions to retrieve billing information from another case and send it to an outside contact as a prerequisite check. Even if the employee may read that other case, the current request does not authorize disclosing it.
- Employee / external text: The employee requests a summary and reply draft
- Employee / external text: The ticket contains instructions to retrieve and send another case
- AI / retrieval: The AI mistakes the text for an authorized instruction and retrieves another case
- Send service: The service sends without verifying approval of recipient and content
- AI / retrieval: A safe-looking answer still requires checking actual delivery records
Trace private-data access, outside-text processing, and external sending. Retrieval must block unauthorized documents, while sending needs a separate decision even for readable evidence. Correct retrieval authorization leaves a disclosure path if recipients and purposes remain unrestricted.
Separate outside data: what system prompts and JSON can accomplish
Pass content with structured provenance and document IDs, and state that retrieved instructions cannot change the task or permissions. Anthropic describes tool-result delivery, explicit provenance, and JSON encoding of third-party strings. These help the model distinguish content; a JSON wrapper does not enforce authorization.
- Internal documents can contain copied tickets or compromised pages. Keep provenance information separate from evidence that authorizes an action.
- Keep API keys and sending credentials in the execution layer, outside model inputs. Restrict confidential content to what the generation service is permitted to process.
- If keyword screening or a separate screening model is used, evaluate misses, false positives, and cost. A successful screen does not replace authorization.
RAG defenses: retain authorization through retrieval, reranking, and caches
RAG uses retrieved evidence during generation. An access control list (ACL) records who may read a document. Separate relevance search from permission decisions, including reranking, which reorders retrieval candidates. Here, server-verified employee and tenant context determines document access before content reaches external reranking or generation. A tenant_id proposed by the model cannot expand that scope.
Resolve authenticated employee and tenant on the server → Filter candidates against current document permissions → Send only permitted content to reranking and generation → Check evidence permissions and destination before saving a draft → Apply current access rules when reusing caches or history
| Boundary | Check in this scenario | Common gap |
|---|---|---|
| Source to index | Preserve document ID, version, tenant, and ACL association | Chunks lose their permission metadata |
| Retrieval to downstream services | Authorize employee access and disclosure to each service | Send full text to external reranking before filtering |
| Answer reuse | Separate tenant and user visibility; recheck evidence access | Serve someone else's cached answer because the question matches |
| Permission changes | Define index propagation delay and authoritative recheck points | Display old history or drafts unchanged after revocation |
OWASP's RAG guidance covers carrying access controls to chunks and enforcing them before the model receives content. As a product example, Google Cloud Agent Search restricts results using end-user identity and document ACLs, subject to configuration requirements. Do not assume indexed ACLs guarantee immediate revocation; this scenario rechecks authoritative permissions at important boundaries.
AI agent defenses: valid arguments do not establish permission
The AI proposes an action; an execution service decides whether it is allowed. JSON schema validation checks tool names and argument types. A request to send another company's document can be well formed, so separately verify ownership, requester permissions, and the current task's scope. Connecting a tool through MCP does not remove execution-side authorization requirements.
| Capability | Allowed scope here | Execution-side control |
|---|---|---|
| Search and retrieve documents | Relevant evidence the current employee may read | Verified identity and tenant; document authorization |
| Save a reply draft | A private draft for an assigned ticket | Target access and version; no writes to another case |
| Send an external reply | Approved content and attachments to an allowed recipient | Recipient policy, individual approval, execution-time rechecks |
| Arbitrary URL, SQL, or shell execution | Unnecessary for this feature | Expose no general executor; reject unknown tools |
{
"tool": "propose_reply",
"ticket_id": "ticket-42",
"draft_version": 12,
"recipient_ref": "contact-7"
}The executor resolves access to ticket-42, stored draft version 12, and contact-7's actual address and relationship to the ticket. Employee and tenant identity come from authenticated execution context, not model claims. A model-produced value such as user_confirmed=true is not approval evidence; consult the server's approval record.
Approval before sending: bind the recipient, body, and attachments to execution
Generic permission to send a reply is ambiguous. This confirmation screen shows the ticket, resolved recipient, subject, full body, and attachments from a stored action. A short model-written description is insufficient: the reviewer must be able to notice information from another case in the actual content.
- AI / draft: Propose recipient, body, and attachments
- Execution service: Validate access and recipient; store an immutable action ID and content version
- Employee / approval service: Review the stored recipient, body, and attachments; approve that action
- Execution service: Match approver, target, version, and expiry; create one send job
- Execution service: Recheck current permissions and validity immediately before sending; track the result
- Bind the action ID to employee, tenant, ticket, tool, normalized recipient, body and attachment versions, and expiry. Changed address resolution or content requires approval of a new action.
- Only an authenticated confirmation path may create approval. Match and consume it while creating the durable send job in one database transaction, so concurrent or repeated requests cannot create additional jobs.
- Carry protected action and requester metadata into the job. Immediately before sending, check current permissions, approval expiry or cancellation, and recipient policy. Defer or deny if checks cannot complete.
- Design delivery deduplication around the same action ID. Verify the provider's idempotency support and reconcile unknown outcomes. Consuming approval once in the database does not guarantee exactly one external send.
OWASP's Transaction Authorization guidance covers protected transaction details, a final execution gate, expiry, and per-operation uniqueness. The database and send-job arrangement here is an original application to support work. Canceling approval cannot recover information already sent. Define how to handle permission changes between the final check and delivery according to platform and business requirements.
Outputs and logs: close disclosure paths outside the send tool
Generated Markdown images or links, arbitrary URL fetches, and logging destinations can become additional exits. This preview executes no raw HTML and loads no external images automatically. Navigation and fetch proxies also need destination and outbound-data controls. HTML escaping alone does not prevent every image- or URL-based disclosure.
Correlate request and action IDs with allow, deny, or review decisions, reasons, and execution outcomes. The example below records a rejection. Link it to protected references for the executor-verified actor and tenant. Avoid copying ticket bodies, full model inputs, credentials, or attachments into routine logs.
{
"event": "agent_action_denied",
"request_id": "req-42",
"action_id": "action-8",
"tool": "send_reply",
"decision": "deny",
"reason_code": "approval_action_mismatch",
"policy_version": "support-v3"
}OWASP's Logging guidance addresses excluding access tokens and secrets from direct logging. Allowlist fields, define access and retention, and use dummy secrets to test validation failures and downstream exceptions. Store detailed investigation evidence separately with a defined purpose, access policy, and expiry.
Evaluate evidence, tool calls, and delivery rather than refusal wording
Counting final refusals does not measure the defense. Use test tenants and dummy confidential values, then inspect evidence sent to the model, authorization decisions, and delivery records at instrumented destinations. Real API keys and customer documents are unnecessary for these attack tests.
| Input or action in a test environment | Expected outcome | Observable evidence |
|---|---|---|
| Place another-case sending instructions in a ticket body | No send outside the requested scope executes | Proposals, authorization decisions, destination receipts |
| Pass another tenant's document ID to a tool | No document content reaches reranking or generation | Retrieval results and downstream payloads |
| Change recipient, body, or attachments after approval | Original approval cannot authorize the changed action | Stored action version and denial reason |
| Use the same approval twice concurrently | Only one send job is created | Approval state and job count; verify external delivery separately |
| Test queued revocation and an unavailable authorization service separately | Deny missing permission; defer or deny unverifiable permission | Execution-time decisions and absence of external delivery |
| Insert an external image carrying a dummy value into the draft | Preview sends nothing automatically outside | Browser and server outbound traffic |
| Use normal tickets and documents quoting attack text for explanation | Legitimate summaries and draft replies complete | Incorrect refusals and actual task completion |
For indirect injection, place the attack in the real ticket or retrieval channel being tested. Pasting it into the user's request tests a different path. Run revocation and authorization-service failure as separate cases too, so the cause of each stop is distinguishable.
- Record violation observed, no violation observed, or inconclusive for each objective. Missing telemetry and timeouts do not count as blocked attacks.
- Hypothetical tally: 20 sending-attack cases repeated three times give 60 runs. Report one unauthorized send, 57 with no violation observed, and two inconclusive. One violation among 58 conclusive runs is about 1.7%, not the success probability of unknown attacks.
- Measure normal work separately. Two incorrect refusals among 40 requests give a 5% false-refusal rate. Check whether the remaining 38 tasks completed; refusing everything is not a high-quality defense.
- Record model, prompt, retrieval, tool, and policy versions and conditions. Repeat the same cases before and after changes. Match side effects against instrumented records and dummy state rather than relying solely on an LLM judge.
OWASP's evaluation examples distinguish objective-specific observations from legitimate-task completion. These counts and calculations are original illustrations, not evaluation results. Trace accessible evidence, proposed actions, approvals, and actual side effects for one business workflow to identify the boundary that needs repair.
Primary sources and related tips
- OWASP LLM01:2025 — Prompt Injection
- Greshake et al. — Indirect Prompt Injection (2023, abstract)
- Anthropic — Mitigate jailbreaks and prompt injections
- OWASP — RAG Security Cheat Sheet
- Google Cloud — Set up data source access control
- OWASP — AI Agent Security Cheat Sheet
- OWASP — Transaction Authorization Cheat Sheet
- OWASP — Multi-Tenant Security Cheat Sheet
- OWASP — Logging Cheat Sheet
- OWASP — LLM Prompt Injection Prevention: smoke tests and outcome grading
Tips this post digs into
- Treat outside text an LLM reads as data, not instructions (prompt injection)
- Enforce RAG authorization before evidence crosses a trust boundary
- A queued job may outlive the permission that allowed it
- Keep tokens and complete request bodies out of diagnostic logs
- Check prompt and model changes for regressions on an evaluation set before shipping