← Blog

Poisoned Tool Descriptions and Cross-Agent Privilege Escalation: Every IAM Call Was Authorized

At DEF CON 34, Microsoft security engineer Muskan Tomar demonstrated cross-agent privilege escalation triggered by a tool description rewritten to read like routine compliance guidance. An agent reads the description and makes an authorized IAM call that raises the privileges of a different agent in a different environment. The reported result across agents built on LangChain and Claude Code is that prompt guardrails, human approval and telemetry each failed in turn. This piece walks the three failures and separates the identity-platform problem from the authorization decision on the request path.

ByParminder Singh· Founder & CEO, DeepInspect Inc.
Problem-Awareai-securityagentic-aiprivilege-escalationtool-poisoningauthorizationmcp
Poisoned Tool Descriptions and Cross-Agent Privilege Escalation: Every IAM Call Was Authorized

The payload was a tool description. Not a prompt, not a document in a RAG corpus, not a support ticket. The text field that tells an agent what a tool does and when to use it, rewritten to read like routine compliance guidance.

Muskan Tomar, a security and reliability engineer at Microsoft, presented this at DEF CON 34 in a talk titled "The Polymorphic Agent: From Cross Agent Escalation to Just in Time Defense on Azure." An agent reads the poisoned description, follows what looks like a policy instruction, and makes an IAM call that raises the privileges of a different agent running in a different environment. Forkast's coverage reports the behaviour reproduced across production agents including ones built on LangChain and on Claude Code.

Every IAM call in the chain was authorized. The agent had the permission. It used the permission. Nothing in the cloud provider's audit trail looks anomalous, because from IAM's point of view nothing anomalous happened.

This is research, presented at a conference, under test conditions. Nobody has reported it exploited in the wild.

Why the description is a good place to hide

An agent's tool description is treated as configuration by the people who write it and as instruction by the model that reads it. That split is the whole vulnerability.

A platform engineer reviewing an MCP server sees a manifest of tools with names, parameters and descriptive text. The review looks like a code review, and descriptive text reads as documentation. The model receives that same text inside its context, where documentation and instruction are indistinguishable, because tokens carry no provenance flag saying which ones the operator wrote and which ones came from a third-party server.

Write the description in the register of a compliance note and it clears both readings. The human sees standard boilerplate. The model sees an instruction from what appears to be an authoritative part of its own configuration.

This is tool poisoning rather than message relay. The distinction matters, because a related failure mode passes authority through a message from one agent to another inside the same system, which is what the Google ADK agent-to-agent escalation case covers. Here the payload sits in the tool catalogue itself, and it reaches every agent that loads that catalogue, in whatever environment each of them happens to run.

The three defences that failed

Tomar's stated conclusions are the part worth sitting with, because each failure is structural.

Prompt-layer guardrails were talked around. A guardrail that inspects the conversation for malicious intent evaluates text against a notion of harmfulness. Compliance guidance is not harmful text. It reads as exactly the thing an enterprise agent should comply with, which is why the register was chosen. The guardrail is a classifier operating on the same ambiguous surface the model operates on, so it inherits the same ambiguity.

Human approval was socially engineered. The approval prompt shown to a reviewer says an agent wants to make an IAM role assignment, with a justification drawn from the poisoned description. The reviewer sees a plausible operational reason, in the same format as the twenty legitimate approvals they cleared that week, and approves. Approval fatigue is a real property of any control that asks a human to adjudicate high-volume, individually-plausible requests.

Telemetry arrived too late. Cloud audit logs recorded the role assignment. They recorded it after it happened, in a stream that a SIEM correlates on a schedule, describing an authorized action by an identity that holds the permission. By the time a detection rule could fire, the escalated role is usable.

Three controls, three different layers, all of them positioned either beside the decision or after it. None of them positioned on it.

The part that is not ours to solve

Being straight about this is worth more than a wider claim.

Cloud IAM policy design is an identity-platform problem. If an agent's service principal holds Microsoft.Authorization/roleAssignments/write, that grant was made by a human in your organization, and a policy gateway on the AI request path does not revoke it. Standing permissions on non-human identities, credential lifetime, role assignment scope, and the two-hop reachability of a given principal across your subscription are all decisions made in the identity platform.

Tomar's own proposed defence, a tool she calls PrivilegeGuard, works at exactly that layer. As reported, it computes a blast radius score for each token request, representing the fraction of cloud resources reachable by a non-human identity across a two-hop IAM graph traversal, and evaluates that score and its rate of change against an Open Policy Agent policy before the token is issued. That is the researcher's own tool and her own architecture, and it targets the credential issuance path rather than the model request path. Worth reading on its own terms.

What I find striking is the shape of the conclusion rather than the specific tool. An independent researcher, working from the failure side, landed on the same structural answer: the decision has to be made out of process, by something the agent cannot talk to.

The slice on the request path

Two things sit on HTTP AI traffic, and only these two should be claimed.

Authorization evaluated per outbound call against the originating identity. An agent chain that starts with a request from a named human and passes through four agents ends with the fourth agent's ambient privilege deciding what happens. Evaluating each outbound AI call against the identity that originated the request, rather than the privilege of whichever agent is executing at that moment, is what breaks the escalation chain at the point where authority gets laundered. This is the practice covered in agent-to-agent authorization and it depends on the identity surviving the hop, which is agent-to-agent authentication.

The per-decision record. One agent acting on another's behalf produces, in most deployments, an API call with a service principal on it and nothing else. A record written on the request path turns that into an attributable authorization event:

  • decision_id: d-5f10a9, recorded at 2026-08-14T14:07:33Z
  • originating_identity: l.marchetti@example.com, the human who started the chain
  • acting_agent: agent-infra-ops, on_behalf_of: agent-ticket-triage
  • hop_depth: 3
  • tool_catalogue_source: mcp-server-vendor-c, the third-party server the tool came from
  • tool_description_hash: sha256:9c1e...4b7f, the hash of the description text the model read
  • requested_action: role_assignment_write
  • policy: agent-privilege-boundary-v2, outcome: denied

The tool_description_hash field is the one that makes tool poisoning detectable after the fact. A description that changed between Tuesday and Thursday, on a third-party MCP server nobody re-reviewed, shows up as a changed hash across otherwise identical decisions. Nothing else in a normal stack records that text at all.

The hop_depth and on_behalf_of pair is what separates an agent doing its job from an agent doing something on behalf of an agent three hops back, which is the specific shape of this attack. The wider gap is covered in the AI agent post-authentication gap, and the framework mapping in the OWASP Top 10 for agentic applications controls mapping.

What to check

Pull the list of MCP servers and tool catalogues your agents load, and mark which ones are third-party. Then answer whether anyone re-reads a tool description after the initial integration review. In most environments the answer is no, and the description is fetched fresh at every agent start.

Check whether your agents' service principals hold any permission that can modify permissions. That is the specific grant that turns a tool-poisoning finding into an escalation chain.

Ask whether an outbound AI call from your fourth-hop agent still carries the identity of the human who started the chain. If the answer is that it carries a service account, the escalation has somewhere to hide.

DeepInspect

This is the gap DeepInspect closes on the request path. DeepInspect is a stateless proxy between your authenticated users, applications and agents and the LLM endpoints they call. Policy is evaluated per request against the identity that originated the session, carried across agent hops rather than replaced by the executing agent's ambient privilege, and every decision produces a record in storage you control.

For an escalation chain built on a poisoned tool description, that means the authorization question is asked at each outbound call by a component running outside the agent's process, with no interface the agent can reach and no natural-language argument that changes the answer. The record names the originating human, the hop depth, and the tool catalogue the instruction came from.

DeepInspect does not design your IAM policy, scope your service principals, or shorten credential lifetimes. Those live in your identity platform and stay there.

If your agents hold standing cloud permissions and you cannot trace a privileged action back to the human who started the chain, that attribution is the first control to build. Book a technical deep dive at deepinspect.ai.