Get the latest, first
arrowBlog
Direct vs Indirect Prompt Injection: The Real Difference

Direct vs Indirect Prompt Injection: The Real Difference

Aug 17, 2026

Shauli Rozen
CEO & Co-founder

Key takeaways

  • What actually separates direct from indirect prompt injection? Only the entry path. Direct injection arrives through a prompt field a user controls, and indirect injection arrives inside data the agent retrieves and treats as content. Both end with attacker-written text sitting in the same context window, read by the same model, carrying the same weight as your system prompt.
  • Why does the two-way split break down in production agent deployments? It was built for chatbots that take a prompt and return text. A production agent ingests untrusted text from at least five places: the prompt, retrieved data, tool and MCP responses, other agents' output, and its own persisted memory. Four of those collapse into a single "indirect" label despite belonging to four different teams.
  • Where should the distinction stop driving decisions? At the context window. Upstream of it, entry path determines which control you build and who owns it. Downstream of it, both attacks produce the same authorized agent running the same unauthorized sequence, so containment has to work without knowing which door the instruction came through.

The difference between direct and indirect prompt injection is a statement about where the payload entered. It is accurate, it is useful for a specific set of decisions, and it stops carrying information at a fixed point in the attack.

That point is the context window. Once injected text is inside it, the model reads it with the same weight as every other instruction it has been given, and the entry path becomes a historical fact rather than an operational one. Everything the agent does next is identical whether a user typed the instruction or a wiki page carried it in.

Two things follow, and neither appears in the standard comparison. The binary undercounts how many ways untrusted text actually reaches a production agent, and it undercounts how many teams are on the hook for closing them. It also implies that two attack types need two containment strategies, when the containment problem is one problem with one shape.

The split classifies entry, and every decision it drives is an entry-time decision

The distinction earns its place in the design phase. Entry path tells you which control to build, where to build it, and which team owns it: a direct injection is intercepted at the request boundary by whoever owns the application, and an indirect injection has to be caught at retrieval time by whoever owns the knowledge base and the connectors.

That is real, load-bearing information. Entry-time controls cut the volume of injected text that reaches the model, and they are the only tier that can stop an attempt before the agent acts on it. Nothing downstream recovers that property.

The taxonomy is also inherited from a context where it was exactly right. In the research literature, entry path is the variable under study: a benchmark measuring whether a defense holds needs to know whether the adversarial string arrived through the user turn or a retrieved document, because the defenses being measured operate on one or the other.

Applied to a Kubernetes cluster running agents with service accounts, the same cut silently imports an assumption. It assumes the interesting part of the attack is the part before the model reads the text.

Production agents have five injection surfaces, not two

Two categories were enough when the system was a chatbot. A production agent reaches untrusted text through five distinct surfaces, and each one has a different instrumentation point.

SurfaceHow untrusted text arrivesNamed by the binary
PromptA user types instructions into the request fieldDirect
Retrieved dataA poisoned chunk surfaces in semantic search and enters contextIndirect
Tool and MCP responseA tool returns attacker-written content the agent treats as trusted outputIndirect
Agent-to-agent outputOne agent’s summary carries an instruction into the next agent’s inputIndirect
Persisted memoryThe agent reads back its own scratchpad or conversation state from a poisoned earlier turnIndirect, by default

Surface three deserves particular attention, because teams routinely treat tool output as trusted. A tool response is attacker-controlled whenever the tool reads anything the attacker can write: a ticket body, a webhook payload, a scraped page, a database row a customer populated through a form. The agent invoked the tool, so the result feels like its own output. The model has no way to make that distinction.

Surfaces four and five have already outgrown the label. OWASP’s Top 10 for Agentic Applications breaks both out into their own risk classes rather than filing them under injection: memory and context poisoning gets ASI06, insecure inter-agent communication gets ASI07. A standards body pulling two surfaces out of a taxonomy is a reasonable signal that the taxonomy was holding them badly.

The practical version of that signal shows up in any multi-agent deployment. We have previously mapped what happens when an instruction rides a delegation edge between agents, where three individually healthy agents produce one breach because each did something on its own authorized capability list.

Five doors. One room.

Past the context window, both attacks converge on the same authorized sequence

Take one agent and run the same attack through two different doors.

A support agent has a customer export tool it uses twice a month for scheduled reporting. In the first scenario, an attacker with portal access types an instruction into the chat asking the agent to run the export and send the file to a partner address on the egress allowlist. In the second, the attacker never touches the agent: they file a support ticket containing the same instruction inside a pasted error log, and the agent picks it up during triage two days later.

Now look at what your telemetry shows, split at the context window.

SignalScenario A (direct)Scenario B (indirect)
Upstream of the context window
Ingestion eventAuthenticated portal sessionRetrieval from the ticket store
Correlated user sessionPresent, attributable to an accountNone
Dwell time before actionSecondsTwo days
Downstream of the context window
Process lineageAgent process invokes export handlerAgent process invokes export handler
Tool invokedcustomer_exportcustomer_export
ParametersFull table, no customer filterFull table, no customer filter
Identity usedAgent service accountAgent service account
Authorization resultPermittedPermitted
Network egressAllowlisted partner endpointAllowlisted partner endpoint
Data volume2,400 records2,400 records

The top three rows differ, and they differ in ways that matter operationally. Indirect injection has no correlated user session to pivot from, and it carries a dwell time measured in days rather than seconds, which is the property that makes stored injection so effective. The distinction does real work right up until the model acts on the text.

Then it stops. Every row below the line is identical, and those are the rows that describe the incident.

The obvious objection is that you log the prompt, so you can tell the two apart. That holds for surface one. It holds for the other four only if you instrumented the ingestion path, tagged content at retrieval and at tool return, and carried that tag through delegation. Most teams have provenance for the prompt field and nothing else, so the rows that distinguish the two scenarios are exactly the rows that go missing when the attack came through a door nobody was watching.

The entry-time tier also has a documented ceiling. Researchers evaluating eight published indirect-injection defenses against an adaptive attacker broke all eight at success rates above 50%, against near-zero figures the original papers reported on static benchmarks. Filtering is worth running and it is not worth trusting, which we have taken apart in why upstream defenses collapse together and what survives downstream.

What both scenarios describe is coercion. The attacker never breaks anything. They redirect an authorized agent into using its own valid permissions in a sequence nobody sanctioned, and every individual step passes every individual check. Your IAM policy fires on unauthorized access, and nothing here is unauthorized. Your egress control fires on unknown destinations, and the destination is on the allowlist. No classic control fires, because from the perspective of each one, nothing wrong happened.

This convergence is good news for control design. Because all five surfaces terminate in the same place and produce the same downstream behavior, one post-entry control covers all five for a given agent. Adding a sixth ingestion surface next year does not multiply the containment work. What it does not cover on its own is the multi-agent case, where each agent stays inside its own envelope and the attack lives on the delegation edges between them. That surface needs the same behavioral approach applied one layer up, at the handoff rather than the workload.

Allocate by convergence point, and name the owner for every surface

Sort your controls into two tiers and the allocation stops being confusing.

Entry-time controls are path-specific and probabilistic: instruction hierarchy, provenance marking, retrieval source allowlisting, input and output classification, human confirmation on high-risk tools. Each surface needs its own, each stops an attempt before the agent acts, and each has a ceiling against an attacker writing for your stack specifically.

Post-entry controls are path-agnostic and behavioral: per-agent baselines, deviation detection, egress constraint, credential isolation, automated containment. One control covers five surfaces, it stops a sequence before it completes, and it cannot stop the instruction from being read.

The tier split is the easy half. The hard half is that the entry-time tier is not one team’s job, and most programs learn this the first time an incident review asks who was supposed to be watching surface three.

SurfaceWho owns the entry-time controlWhat that team can see from where they sit
PromptApplication teamThe full request, the session, the authenticated identity behind it
Retrieved dataKnowledge base and connector ownersWhat was indexed and when, but not which chunk surfaced in which query
Tool and MCP responseIntegrations teamThe tool contract and the response schema, rarely the response content
Agent-to-agent outputOrchestration ownerThe delegation graph, rarely what an instruction became by the third hop
Persisted memoryPlatform teamWhere state is stored, almost never what a prior turn wrote into it

Read the right-hand column as a coverage map. Each team sees the surface it owns and nothing of what the text does after it leaves them, which is why an entry-time program built from five separately reasonable decisions still ends up with gaps between them. Nobody owns the seam.

The post-entry tier is the only place in the architecture where all five paths are visible at once, because it sits after the merge. That is an organizational argument as much as a technical one: a single control at the convergence point is the only thing one team can be held accountable for across all five surfaces.

None of this removes the reason to run entry-time controls. Every attempt stopped at the door is an incident that never needs a response.

The tier most teams are missing needs a definition of normal before it can do anything.

Build the post-entry control from the agent’s own behavior

A post-entry control has one job: notice that this agent has stopped behaving like itself, and act before the sequence completes.

That requires a baseline built from what the agent actually does rather than what its manifest declares. ARMO builds it per agent and calls it Application Profile DNA (APD™): the processes it runs, the files it touches, the syscalls it makes, the destinations it reaches, the tools it invokes and in what order. The recording comes from an eBPF sensor at the kernel level, which is why it needs no sidecars and no code changes, and why it runs at 1 to 2.5% CPU and roughly 1% memory.

The property that matters here is structural. The deviation math never reads the entry path, because the entry path is not one of its inputs. An export tool fired outside its schedule against an unfiltered table is a deviation from this agent’s own profile whether a user typed the request or a ticket carried it. The control is path-agnostic by construction, which is what makes one of it sufficient for five surfaces.

The reasonable objection is that a control which blocks things will eventually block the wrong thing and take production down at month end. That objection is why enforcement runs in two stages. In Audit, the platform logs every action the policy would have blocked and blocks nothing, so you find the quarterly reconciliation job and the rare legitimate batch before either becomes an outage. Enforcement turns on per agent once the audit log is clean, along the progressive path from observation to enforcement.

Credential isolation closes the loop from the other side. When the agent holds substituted keys and real credentials are swapped in only for sanctioned operations, a coerced agent that clears every other check still fails at the point where it tries to use something real.

What the SOC receives is one attack story rather than a queue: the agent, the instruction that redirected it, the tool it misused, the identity it used, the data it touched and the destination it reached, on a single timeline. Producing that timeline is the whole job of runtime security for AI workloads.

One convergence point, one control to defend it

Direct and indirect are five surfaces wearing two labels, and all five terminate in the same context window. Build entry-time controls per surface, because each door needs its own lock, each has a different owner, and each attempt stopped there is an incident you never have to investigate. Build one post-entry control for the convergence point, because after it the two attacks are one attack.

The distinction is still worth keeping. It tells you where to reduce the arrival rate and who to put on it. It cannot tell you what the agent did next, and in production that is the question the SOC is holding.

Watch a demo to see what a coerced agent looks like against its own baseline.

Frequently Asked Questions

Is indirect prompt injection harder to detect than direct? Upstream of the context window, yes, and by a wide margin. The payload arrives through the data plane with no correlated user session and a dwell time measured in days, so there is often nothing to pivot from when you go looking. Downstream, the two are equally hard, because the runtime behavior they produce is the same. Split the question by tier before you answer it, or you will buy an entry-time control to solve a containment problem.

How do I get provenance on the tool and agent-to-agent surfaces? Tag content at the boundary where it enters the agent’s context: at retrieval for RAG chunks, at tool return for MCP and API responses, at handoff for orchestration output. Carry the tag through the delegation chain rather than regenerating it per hop, or it stops meaning anything by the third agent. Then correlate by workload identity so provenance and runtime telemetry land in the same incident. The production detection chain for prompt injection walks the telemetry requirements stage by stage.

Which team should own the memory and context surface? Whoever operates the state store, which in practice means the platform team rather than the application team that wrote the agent. This surprises people, because the poisoning happens in application logic and the consequence appears in application behavior. Memory is usually shared infrastructure serving several agents, so an application-team fix protects one and leaves the rest exposed.

Do direct and indirect prompt injection need separate detection rules? They need separate entry-time controls and one shared post-entry control. Each surface has a different owner and a different instrumentation point, so provenance marking at retrieval is different work from instruction hierarchy in the request handler. Two sets of behavioral detection rules duplicate budget for no coverage gain, because both paths produce the same deviation from the same baseline.

Is the direct versus indirect split still worth keeping in our threat model? Keep it for the prevention half of the document and retire it from the detection half. It maps cleanly onto control ownership, which is exactly what a threat model needs to assign work. It maps onto nothing useful once you are writing detection logic or an incident runbook, and carrying it there produces two response paths for one incident shape.

Close

Your Cloud Security Advantage Starts Here

Webinars
Data Sheets
Surveys and more
Group 1410190284
Ben Hirschberg CTO & Co-Founder
Rotem_sec_exp_200
Rotem Refael VP R&D
Group 1410191140
Amit Schendel Security researcher
slack_logos Continue to Slack

Get the information you need directly from our experts!

new-messageContinue as a guest