SAFEPENTEST

Indirect prompt injection: the attack that scales with your agents

Every new data source an agent reads is a new place to plant instructions. How indirect prompt injection turns into unauthorized actions, and the controls that actually reduce the risk.

Prompt injection is listed first in the OWASP Top 10 for LLM Applications (LLM01:2025) for a reason. But the version that matters most for autonomous agents is not the one where a user types “ignore your previous instructions”. It is the one where nobody types anything to the model at all.

In indirect prompt injection, the attacker plants instructions in content the agent will later read: a support ticket, a product review, a web page, a shared document, an email, a calendar invite, a code comment or the output of another tool. MITRE ATLAS tracks this as LLM Prompt Injection: Indirect (AML.T0051.001).

Why it scales

Direct prompt injection needs access to the conversation. Indirect injection only needs write access to something the agent reads, and agents are built to read a lot.

Every connector you add, whether it is search, email, a ticketing system or a document store, extends the set of people who can influence your agent’s decisions. Most of those people are not your users, and some of them are attackers.

From text to action: a typical chain

A typical chain, as reproduced in lab environments:

  1. Untrusted content. An external user submits a support ticket containing hidden instructions.
  2. Prompt injection. A triage agent reads the ticket as part of its normal job.
  3. Agent decision manipulation. The instructions convince the agent that a different action is needed.
  4. Tool invocation. The agent calls an account-management tool with attacker-chosen arguments.
  5. Unauthorized business action. The tool executes, because it trusts the agent, and the agent trusted the ticket.

Notice where the actual vulnerability is. The model being “fooled” is expected; models cannot reliably separate instructions from data. The exploitable flaw is step 4: a tool that accepts the model’s arguments without checking who the action is for.

Controls that reduce the risk

There is no single filter that solves prompt injection, and products that promise one should be tested, not trusted. What works is limiting what a successful injection can achieve.

  • Bind tools to identity, not to the model. A tool that changes an account should act on the authenticated user’s account, derived from the session, never from an argument the model supplies.
  • Validate every argument against a strict schema. Types, ranges, allowlisted values. Reject anything else instead of trying to interpret it.
  • Separate read and act. Agents that read untrusted content should not hold the permissions to perform high-impact actions directly.
  • Require human approval for high-stakes actions, especially when the request originated from untrusted content.
  • Scope authorization to the session in asynchronous and multi-agent workflows, so a background task cannot act with more privilege than the user who started it.
  • Log tool calls with their provenance, so you can tell which input led to which action.

How to test for it

Testing indirect injection means thinking like the attacker who never talks to your agent:

  • Map every source of content the agent reads and who can write to each one.
  • For each source, plant instructions that target the agent’s most powerful tools.
  • Run multi-turn scenarios, since many guardrails only inspect a single message.
  • Measure outcomes as actions, not words: did a tool execute that should not have?
  • Repeat after every prompt, model or tool change, because fixes regress.

The takeaway

You cannot stop an agent from reading hostile text, so design for the case where it believes it. Security comes from what the agent is allowed to do after that, and from verifying those limits the way an attacker would.