← Blog

Identity & access · · 7 min read

The lethal trifecta: where it actually lives

Untrusted inputs + private data access + outbound communication. The framing names the risk space correctly; the standard mitigation pattern picks the wrong layer.

Jonathan Haas

A pattern named in mid-2026 industry conversations: the lethal trifecta. An agent that has all three of these properties at once is, in the framing's authors' view, exposed to an entire class of attacks that no single defense layer can fully prevent:

  1. Untrusted inputs — the agent reads content it does not control. User prompts, tool outputs, web pages, ticket bodies, customer documents.
  2. Private data access — the agent has authority to reach data the operator behind it would not want exposed. Tenant tables, internal documents, customer records, source code.
  3. Outbound communication — the agent can act in a way that leaves the system. API calls, network requests, file writes that are read by other systems, message sends.

The framing has been picked up across security blogs and incident-response writing through the first half of 2026 (Airia blog). It's correct in the sense that the combination is what makes catastrophic incidents possible. It's incomplete in the sense that the defense pattern most often paired with it picks the wrong enforcement layer.

Why the three together are the problem#

The legs are individually old. Programs have always processed untrusted input. Programs have always had access to private data. Programs have always sent messages to other systems. What makes the combination dangerous in an agent is that the agent's decision to act on the input is not constrained by code review: the agent decides at runtime what to do with what it reads. A static program with untrusted input + private data access + outbound communication still does only what its code does, every run. An agent in the same configuration does what the model decides — and the model's decisions are conditioned on the input.

The classical attack pattern in this configuration: an attacker inserts an instruction into a piece of content the agent will read (a ticket, a document, a webhook payload). The instruction asks the agent to do something with the private data it has access to, then send the result somewhere the attacker can receive it. The agent reads the content, interprets the instruction, performs the data access (legitimate, since it has authority), constructs the outbound message (legitimate, since it has authority), and sends it. From the SIEM's perspective, every step was an authorized action by the agent's service identity. The breach is invisible at the action layer.

The standard mitigation pattern#

The standard response is to layer model-side defenses: a prompt-injection classifier on inputs, a content classifier on outputs, an instruction-following monitor on the model. The intuition is that if the attack vector is "the model interprets untrusted text as an instruction," the defense should sit at the model — recognize the malicious text, refuse to follow it.

This is the right idea for a narrow band of attacks: cases where the malicious instruction is recognizable as malicious. It fails on three broader classes.

First, the attack does not have to look malicious. A legitimate-sounding instruction in a ticket can produce the same outcome. The classifier has no signal to detect because there's no anomaly in the input.

Second, the model can decide to perform the data access without an injection at all. The lethal-trifecta framing is sometimes presented as if the prompt injection is the trigger. In practice, the cross-tenant reach incident class — agents reading data they were never scoped to — usually involves no injection: the agent decides on its own that reading the adjacent data is the right thing to do.

Third, the classifier itself is the wrong altitude for enforcement. The model can decide to call a tool; whether that tool call is authorized is a question for the identity layer. A model-side classifier that says "don't do this" can be ignored by the same model on the next turn; an identity-layer denial cannot.

Where each leg actually has to be controlled#

The three legs each have an architecturally correct enforcement layer, and they are not the same layer.

Untrusted inputs. The correct enforcement is upstream of the model: input provenance and trust labeling. The runtime tracks which parts of the agent's context window came from which source (the operator's prompt, retrieved documents, tool outputs) and propagates that provenance into the decisions downstream. When the agent attempts a sensitive action, the runtime can consider not only the action but which input class it was provoked by. This is the layer simon Willison and others have written about as "trust-tracking"; in 2026 it's becoming standard in mature agent stacks.

Private data access. The correct enforcement is at the identity layer. The agent's identity for the run carries the scope it is allowed to access; the policy gate refuses requests outside that scope. If the agent is helping customer A, the gate refuses reads of customer B's data — not because the model is malicious, but because the identity isn't scoped to it. The model can decide to attempt the read; the gate decides whether it happens.

Outbound communication. The correct enforcement is at the egress layer: an allowlist of destinations the agent can reach, with a separate policy for outbound payloads. A model that has been induced to construct an exfiltration payload still cannot send it if the runtime's egress policy doesn't have the destination on the allowlist. The egress check sees the destination clearly; the model's self-restraint can be talked out of refusing.

Where the lethal trifecta lives in your architecture#

The mistake the standard mitigation pattern makes is concentrating the defense at one layer (the model) when the three legs of the trifecta are enforced at three different layers. Each layer has different threat assumptions, different latency budgets, and different observability.

Input provenance lives in the orchestrator — the layer that constructs the agent's context window from operator input, retrieved documents, and tool outputs. It is cheap to track; the runtime knows where each chunk came from. The cost is design discipline: the agent's prompt-construction code has to propagate provenance instead of flattening everything into one block of text.

Identity-scoped access control lives in the policy gate. The latency budget is the per-action evaluation cost (Microsoft Agent OS targets sub-millisecond). The observability is the audit log: every refused action is a row, every allowed action is a row, the security team can query both.

Egress control lives in the network layer, or in an MCP gateway that intercepts outbound tool calls. The latency budget is per-egress; the observability is the network log plus the audit row that records what the agent tried to send.

Each layer carries its own latency budget and its own observability primitives. The model-side classifier is a fourth layer, useful as defense in depth, but never the load-bearing one.

Concrete: a 2026-style incident#

In March 2026, public reporting documented a financial services company whose customer-facing AI agent had been leaking internal pricing data for three weeks before discovery (Aimagicx blog). The attacker had inserted a carefully worded question that caused the agent to expose data it had access to.

In the lethal-trifecta framing, this incident maps cleanly: untrusted input (the attacker's question), private data access (the agent's authority over pricing data), outbound communication (the agent's responses returning to the attacker). Three legs, all enabled.

In the standard-mitigation framing, the defense should have been a model-side classifier that recognized the attacker's question as adversarial. That layer either wasn't present or didn't fire.

In the architectural framing the previous section described, the defense was missing at the identity layer. The agent's service identity had read access to internal pricing data because the integration was designed around "the agent can answer questions about pricing." The identity wasn't scoped to which prices the customer was allowed to see, and the gate had no signal to deny on a question that looked legitimate. The fix is identity scope that the gate can evaluate without depending on the model's self-restraint.

What this means for runtime design#

The lethal-trifecta framing is useful precisely because it names a combination that would otherwise be analyzed as three separate problems. The cost of accepting the framing without inspecting where each leg is enforced is that teams concentrate their defensive investment on the wrong layer.

A runtime that takes the framing seriously will have three things:

  • Input provenance threaded through the agent's context, so the orchestrator can pass it down to the policy gate.
  • A policy gate that scopes data access by run, with the operator's identity as the source of truth for what the agent is allowed to reach.
  • An egress layer that allowlists destinations and inspects outbound payloads against the scope.

None of the three is the model itself — each is runtime infrastructure that surrounds it, evaluated before or alongside whatever the model decides to do.

Deixic's runtime enforces the identity and policy layers. The egress and provenance layers are still part of the buyer's stack; the gate accepts provenance signals as input. See What you can do for the surfaces that emit and consume those signals.