Agentic architecture
Partial12 minCross-Agent Prompt Injection
In a multi-agent system, a prompt injection that lands in one agent propagates to another — because one agent’s output is another agent’s input, or because supposedly isolated agents share a writable channel. A single infection becomes a cascade.
Classification
- Domain
- Agentic architecture
- ROOTVIEL support
- Partial — Core is built; parts are not yet wired end-to-end.
- Analysis family
- FAM-GENAI-STATIC
- CWE
- CWE-514, CWE-653
- OWASP
- LLM01
Definition
Cross-agent prompt injection is the propagation of an injected instruction from one agent to another within a multi-agent system. The payload lands in agent A — through a retrieved document, a tool result, or a user message — and then spreads, because A’s output flows into agent B’s context, or because A and B share a channel one can write and the other can read. What was a single-agent injection becomes a system-wide one.
The distinguishing property is propagation across an isolation boundary. Designers often reason about each agent’s safety in isolation; cross-agent injection exploits the wiring between agents — the message passing and shared state that make the system a system.
Context
This appears in any orchestrated multi-agent setup: a planner that delegates to worker agents, a pipeline where each agent consumes the previous one’s output, a shared blackboard or scratchpad several agents read and write, or a message bus connecting specialised agents. The more agents exchange data, the more surfaces exist for an injection to hop across.
- ▸Planner/worker architectures where the planner’s output becomes a worker’s instruction.
- ▸Pipelines where agent N’s output is agent N+1’s input, chaining trust.
- ▸Shared scratchpads, blackboards, or message buses that multiple agents read and write.
Technical fundamentals
Two distinct mechanisms carry the infection, and they call for two distinct invariants. The first is cascade: an injected instruction in A’s output is consumed as trusted instruction by B. The invariant is “a poisoned output must not propagate across agents” — B must not treat A’s output as instruction-bearing without a trust boundary. The second is the covert channel: two agents the design believes are isolated in fact share a channel one can write and the other can read. The invariant is “isolated agents must not share a writable channel”.
Both are dataflow properties over a graph of agents and channels, not over a single context window. Reasoning about them soundly means modelling edges between agents (output→input wirings) and shared stores (write and read wirings), and asking whether a poisoned value can travel an edge to a place where it causes harm.
- Cascade
- A poisoned output from one agent consumed as trusted input by a second agent.
- Covert channel
- A shared store two nominally-isolated agents can write and read, allowing data to cross the isolation boundary.
- Cascade invariant
- “A poisoned output must not propagate across agents.”
- Covert-channel invariant
- “Isolated agents must not share a writable channel.”
- Wiring
- A proven edge in the agent/channel graph — an output→input link, or a write/read link to a shared store.
Root cause
The defect is that inter-agent communication carries no trust boundary. One agent treats another agent’s output as trusted instruction (there is no provenance on the edge), or agents assumed to be isolated are wired to a common writable store the architecture never accounted for. The deeper cause is reasoning about agent safety in isolation while the harm lives in the composition — the edges between agents, not the agents themselves.
How the attack works, step by step
- 1An injection lands in agent A — via a retrieved document, a tool result, or a user turn.
- 2A produces output that carries the injected instruction forward (verbatim or transformed).
- 3Cascade path: A’s output is routed to agent B as input; B, lacking a trust boundary, treats it as instruction.
- 4Covert-channel path: A writes to a store that B — nominally isolated from A — can read, so the payload crosses the boundary without a direct edge.
- 5B acts on the injected instruction; if B holds a privileged capability A lacked, the infection has escalated.
- 6A privileged action by the now-infected holder completes the chain: the injection has propagated and produced a real effect.
Vulnerable example
A synthetic, illustrative two-agent pipeline where the worker trusts the planner’s output as instruction, and both share a writable scratchpad:
synthetic — do not use; illustrates the flaw# UNSAFE: planner output is trusted as instruction; a shared scratchpad links the two. scratch = SharedStore() # both agents can write and read def planner(user_task): docs = retrieve(user_task) # may carry an injected instruction out = model_A(SYSTEM_A + "\n" + "\n".join(docs) + "\n" + user_task) scratch.write(out.notes) # writes to the shared channel return out.plan def worker(plan): notes = scratch.read() # reads whatever planner (or anyone) wrote out = model_B(SYSTEM_B + "\n" + plan + "\n" + notes) # plan+notes trusted as instruction if out.tool_call: run_privileged(out.tool_call) # worker holds the privilege; injection escalates
Corrected example
The fix puts trust boundaries on the edges. Inter-agent messages carry provenance and are consumed as data, not instructions; the shared channel is removed or made one-directional with validation; and the privileged worker gates its action deterministically, so a propagated instruction cannot, by itself, authorize it.
synthetic — provenance on edges + deterministic action gate# SAFER: messages are provenance-tagged data; no shared writable channel; gated action. def planner(user_task): docs = retrieve(user_task) # each doc keeps source + trust out = model_A(build_prompt(SYSTEM_A, user_task, data=docs)) return tag(out.plan, source="planner", trust="low") # passed as data, not instruction def worker(plan_msg): out = model_B(build_prompt(SYSTEM_B, data=[plan_msg])) # plan consumed as delimited data action = out.proposed_action # the model only PROPOSES if action and policy.allows(action, origin=plan_msg.source): run_privileged(action) # deterministic gate, outside the model else: deny(action, reason="not authorized from this origin")
Limit of the fix: provenance tagging reduces a cascade’s reach but does not make a worker immune to a persuasive low-trust message. The decisive controls are removing the shared writable channel and gating the privileged action deterministically.
Impact
- ▸Escalation: an injection in a low-privilege agent reaches a high-privilege one, gaining capabilities the original foothold lacked.
- ▸Blast radius: one poisoned input can steer a whole fleet of agents, not just the one it landed in.
- ▸Stealth: a covert channel lets the payload cross a boundary the architecture believes is sealed, so the path is invisible on the intended topology.
- ▸Integrity/Authorization: the privileged agent performs attacker-chosen actions attributed to the system.
Detection
Static analysis can model the agent/channel graph and test both invariants: whether a poisoned output can travel an output→input edge into a second agent (cascade), and whether two nominally-isolated agents share a store one can write and the other read (covert channel). The honest signal is proven wiring — a demonstrated edge, not an assumed one. Dynamic testing can inject a canary into one agent and observe whether another agent acts on it, confirming propagation end to end.
How ROOTVIEL analyzes it
- Support level
- Partial — a Python-centric static analysis over the agent/channel graph; it reasons about proven wirings, not about a demonstrated live cascade.
- Family
- GenAI (static) — findings rest on the code graph and proven edges.
- Declared invariants
- “A poisoned output must not propagate across agents” (cascade) and “isolated agents must not share a writable channel” (covert channel).
Two verifiers run over the graph. The cascade verifier FAILS only when BOTH conditions are proven: the poisoned output provably spreads to a second agent, AND a privileged act by the now-infected holder is proven. Either leg alone is not a failure — spread without a reachable privileged act, or a privileged capability with no proven spread into it, is insufficient. The covert-channel verifier FAILS only when BOTH the write wiring (agent A can write the store) and the read wiring (agent B can read it) are proven; if only one wiring is proven, the shared-channel claim is not established.
Honest discipline: where the required wirings are not both proven, the verifier returns UNKNOWN — never a finding and never “secure”. A confirmed cross-agent finding requires the full proven chain (spread + privileged act, or write + read). Assumed or synthetic edges do not satisfy it. ROOTVIEL does not demonstrate the live cascade; it proves the structural path.
Mitigation
Put trust boundaries on the edges and starve the covert channels.
- ▸Preventive (cascade): carry provenance across inter-agent messages; consume another agent’s output as delimited data, not instructions; gate any privileged action deterministically regardless of which agent proposed it.
- ▸Preventive (channels): eliminate shared writable stores between agents that are meant to be isolated; where a channel is needed, make it one-directional and validated, and record who may write and who may read.
- ▸Detective: model the agent/channel graph and flag cascade edges and write+read pairs; inject canaries into one agent and watch for action in another.
- ▸Corrective: scope each agent’s privileges to the minimum; isolate blast radius so an infected worker cannot reach system-wide capability.
Verifying the mitigation
Verify across the boundary, not within one agent: inject a canary instruction into agent A and confirm agent B treats A’s output as data and does not perform the enjoined action; attempt to pass a payload through any shared store and confirm the channel is absent or validated; re-run the static analysis and confirm no cascade chain (spread + privileged act) and no write+read covert-channel pair remains. Report as “the defense held within the tested scope”.
A per-agent test proves nothing about propagation — verification must exercise at least two agents and any store between them.
Common mistakes
- ▸Reasoning about each agent’s safety in isolation and never about the edges between them.
- ▸Treating another agent’s output as trusted instruction rather than provenance-tagged data.
- ▸Leaving a shared scratchpad or bus that nominally-isolated agents can both write and read.
- ▸Assuming a topology diagram is the real wiring — a covert channel is exactly the edge the diagram omits.
- ▸Reading an incomplete chain as safe — one proven leg without the other is UNKNOWN, not secure.
References
- [1]OWASP Top 10 for LLM Applications — LLM01 Prompt Injection
- [2]OWASP Agentic Security Initiative — Multi-agent and orchestration threats
- [3]MITRE CWE-514 (Covert Channel)
- [4]MITRE CWE-653 (Improper Isolation or Compartmentalization)
References point to public, well-known technical sources for further study.
Related articles
