Source Authorization in LLM Agents
- Source Authorization is the process of verifying concrete tool call arguments, ensuring that allowed values match strict authorization policies.
- It distinguishes capability gating (menu-level control) from runtime per-call checks, preventing confused-deputy failures in LLM systems.
- Research shows that popular frameworks lack deterministic, fail-closed authorization, with proposals like ScopeGate providing rigorous enforcement.
Capability-gated tool access in LLM agents is an authorization problem, not merely a schema-validation problem. In tool-using systems that read untrusted content while holding side-effecting tools such as payments, email, CRM, and infrastructure APIs, the central claim of "Capability Gates Are Not Authorization: Confused-Deputy Failures in LLM Agent Frameworks" is that exposing a tool to the model does not answer whether a specific model-emitted invocation with concrete argument values is permitted. The paper argues that if a runtime accepts parsed, well-typed tool arguments as sufficient authority, then the model becomes the de facto authorization oracle, producing a classic confused-deputy failure mode; its audit of LangChain/LangGraph, LlamaIndex, and the Stripe Agent Toolkit finds capability gating by default but no deterministic fail-closed per-call value authorization gate by default (Zuvic, 27 Jun 2026).
1. Capability exposure and authorization are distinct controls
The paper distinguishes sharply between capability gating and true source/value authorization. Capability gating is a menu-level control: it decides whether the model can call a tool at all, whether a tool exists in the registry, and whether the argument schema type-checks. True authorization asks a different question: whether the exact call is allowed, whether the concrete argument values are permitted for the current principal or session, and whether policy allows the transaction amount, destination, account, URL, or intent (Zuvic, 27 Jun 2026).
This distinction is central because a schema can validate shape but not authority. A well-typed argument such as account=acct_ATTACKER_999 remains unauthorized if the verified set permits only acct_MERCHANT_001. The paper therefore treats type correctness as orthogonal to authorization correctness. In this model, tool existence, name resolution, and argument parsing are necessary operational steps, but they are not authorization decisions.
A broader implication is that any runtime that treats model-emitted structured arguments as self-authenticating collapses the boundary between planning and permission. The paper’s terminology is explicit: tool exposure is not authorization. That formulation rejects the common assumption that a registered tool plus a valid JSON shape is enough to justify side effects.
2. Confused-deputy failures in tool-using agents
The paper frames the vulnerability as a classic confused deputy. The runtime or tooling is privileged; the model is an untrusted parser/planner over text; attacker-controlled content influences the model’s proposed tool call; and the runtime then executes that call using its own authority (Zuvic, 27 Jun 2026). The deputy is therefore “confused” into exercising authority on behalf of attacker-controlled input rather than on behalf of a verified principal intent.
The failure surface is broad because the triggering condition is not malformed output but syntactically valid output with unauthorized semantics. The paper lists harmful but valid-looking actions such as payout to an attacker account, refund to an attacker destination, secret exfiltration, and SSRF or infrastructure calls. The danger arises specifically when untrusted content and side-effecting tools coexist in the same execution path.
This mechanism aligns with the broader open-world-agent literature on the Authorization-Execution Gap (AEG), defined as the divergence between what a principal intends to authorize and what an open-world agent ultimately executes (Wu et al., 10 May 2026). In that broader framing, unauthorized action execution, unauthorized disclosure, and persistent corruption are downstream manifestations of the same mismatch. The confused-deputy analysis in (Zuvic, 27 Jun 2026) can be read as a concrete runtime instance of channel-level corruption during execution, where environmental content becomes actionable without being treated as untrusted.
3. Cross-framework audit of default dispatch behavior
The audit asks a narrow, operational question: after the model emits a tool call, is there a deterministic fail-closed authorization check over the concrete arguments before side effect? Across pinned public-source commits and versions, the paper’s answer is negative for all three audited stacks by default (Zuvic, 27 Jun 2026).
| Stack | Default provided | Not provided by default |
|---|---|---|
| LangChain / LangGraph | Capability gating; schema validation | Deterministic fail-closed per-call authorization over concrete values |
| LlamaIndex | Tool-name existence; schema-shape checks | Deterministic per-call value authorization |
| Stripe Agent Toolkit | Static action allowlists; Stripe restricted API key scope | Per-transaction re-authorization of model-supplied values |
For LangChain, the audited path is a model output parser producing something like AgentAction(tool, tool_input, ...), followed by a dispatcher resolving name_to_tool_map[agent_action.tool] and calling tool.run(tool_input, ...). For LangGraph, ToolNode._run_one resolves tools_by_name.get(call["name"]) and invokes the tool. The finding is that these paths provide capability gating and schema validation, but no default fail-closed per-call authorization over concrete values before execution. Callback hooks are characterized as observability rather than a mandatory veto, and human-in-the-loop middleware can be added but is not the default complete-mediation boundary (Zuvic, 27 Jun 2026).
For LlamaIndex, the central dispatch checks that the tool name exists in tools_by_name and then calls the selected tool with model-supplied keyword arguments. The paper again finds tool existence and schema-shape checks, but not deterministic per-call value authorization by default. Human-in-the-loop behavior occurs only if tool authors explicitly build it into workflow code (Zuvic, 27 Jun 2026).
For the Stripe Agent Toolkit, the case is treated as especially sensitive because it sits near money-moving operations. The toolkit exposes coarse controls such as static action allowlists and Stripe restricted API key scope, but the paper classifies these as capability-level controls rather than per-transaction authorization. The public toolkit forwards model-supplied values such as amount, currency, customer, payment_intent, price, quantity, and redirect_url, and therefore does not re-authorize each model-emitted money-related call with concrete arguments before execution (Zuvic, 27 Jun 2026).
4. ScopeGate and deterministic fail-closed mediation
As a reference control, the paper introduces ScopeGate, a deterministic Policy Decision Point / Policy Enforcement Point placed downstream of the model and upstream of side-effecting tools. It receives a proposed tool call c=(name,args), trusted context , and operator-authored policy , and returns either Allow or Deny; no LLM participates in the decision (Zuvic, 27 Jun 2026).
The decision rule is written as:
Its five stages are:
- Scope: if the tool name is not in policy tools, return
Deny(scope). - Authorization: for each allowed-argument constraint, if the value is not in the allowlist, return
Deny(authz). - Money ceiling: for money tools, let and allow only if
otherwise return Deny(money).
- Idempotency: if a side-effecting tool needs idempotency and no trusted idempotency key is present, return
Deny(idempotency). - Default deny: only calls passing all checks are allowed; runtime errors return
Deny(error).
The paper emphasizes that ScopeGate fails closed on policy miss or runtime error. It also stresses that the money-ceiling check is an affirmative validity test, not merely a comparison: NaN, infinities, booleans-as-integers, and nonnumeric containers are denied (Zuvic, 27 Jun 2026).
The policy model is operator-authored and out-of-band. It includes tool scopes, allowlists, money ceilings, idempotency requirements, and verified sets such as . The paper states that these policy elements must not be sourced from model output, directly or indirectly; policy data must come from a trusted root outside the model’s context window and write path. Its normative rule is correspondingly strict: no policy element may originate from any LLM output, policy must remain immutable during the conversation, and every access to authority must be mediated. This is the complete-mediation principle applied to tool calls (Zuvic, 27 Jun 2026).
5. Evaluation, attack suites, and measured outcomes
The evaluation has two aims: to show that the default dispatch gap is real and to test whether ScopeGate blocks unauthorized calls without over-blocking benign ones. The concrete LangChain proof of concept uses update_payout_account and issue_refund against a mocked merchant backend. A compromised model output proposes
and the result differs completely by enforcement path: unguarded framework dispatch executes the payout and records a side effect, whereas the ScopeGate-guarded path denies at authz because the attacker account is not in the verified set, with zero side effects recorded. The paper also includes a companion LlamaIndex proof of concept showing the same default dispatch gap (Zuvic, 27 Jun 2026).
The static bypass suite contains 48 adversarial vectors, including case, whitespace, zero-width, homoglyph, null-byte mutations, type confusion, unhashable arguments, tool-name mutations, money edge cases, and missing idempotency. The reported result is 0/48 bypasses. The paper notes that an internal prototype bug initially allowed NaN through a naive money comparison, but the current range check denies NaN; this was a prototype bug, not a framework bug (Zuvic, 27 Jun 2026).
The adaptive attacker experiment is a 40-iteration adaptive run in which the attacker uses deny reasons to adapt. The reported results are 0/29 unauthorized attempts allowed, 29 denied, 9 malformed/parse errors, and 2 benign calls allowed. The paper explicitly characterizes this as bounded evidence rather than a universal proof. The benign-control set contains 10 benign controls with 0/10 false-denies. In the Latam-GPT payment-agent containment experiment, 10/10 unauthorized payout attempts are denied; the model attempted unauthorized payout actions in all trials, and ScopeGate blocked them all. A broader containment vignette reports 11/11 harm-bearing egress actions denied in the exercised scenarios (Zuvic, 27 Jun 2026).
The paper also reports a separate susceptibility sweep over model classes. Deployment-tier models show mean attempted unauthorized-call rate 0.603, while flagship models show mean 0.189, so deployment-tier models attempted unauthorized calls about 3.2× more often in that sweep. The paper is careful to say that this is attempt rate, not breach rate, and that the tier grouping is an economics/deployment inference rather than a claim about provider production operations (Zuvic, 27 Jun 2026).
6. Limits, controversies, and relation to adjacent authorization frameworks
The paper is explicit about scope. Containment is not a cure: ScopeGate does not prevent prompt injection, does not detect poisoned weights, and does not repair model behavior; it only bounds what a compromised model can do through governed tools. The quantitative results are bounded by the written vectors and attacker budget; there is no universal bypass-impossibility proof. No live third-party service was attacked, no real payment or egress occurred, remote Stripe MCP internals were not audited, the findings concern public-source client and framework defaults and design postures, and no CVE is asserted (Zuvic, 27 Jun 2026).
These limitations place the work inside a broader shift in agent security toward execution-time authorization integrity. The AEG position paper argues that authorization integrity cannot be guaranteed by one-shot upfront filtering or only post-hoc audit, because critical divergences arise during execution and handoff; it therefore proposes checks such as Authority Attribution Check, Scope Compliance Check, and Recomposition Authorization Check during execution (Wu et al., 10 May 2026). This suggests that the per-call mediation demanded in (Zuvic, 27 Jun 2026) is one instance of a wider architectural principle.
Two contemporaneous lines of work extend that principle along different axes. Intent-Governed Access Control (IGAC) treats the user’s expressed intent as a monotone, auditable policy attribute for agent tool use and enforces the invariant that user intent may only reduce authority, never expand it (Zhu et al., 22 Jun 2026). AuthGraph introduces a dual-graph defense that compares execution provenance against an authorization graph derived in a clean, isolated context, enabling parameter-source-level checks such as whether a value used in book_flight.flight_id originated from the authorized tool observation rather than from an injected hotel listing (Wang et al., 26 May 2026). Relative to those systems, the contribution of (Zuvic, 27 Jun 2026) is narrower but precise: a framework-level demonstration that capability gates and schema checks do not constitute authorization, together with a deterministic fail-closed per-call mediation pattern built around scope, authorization, money ceiling, idempotency, and default deny.
The resulting bottom line is doctrinal rather than framework-specific. In tool-using LLM systems, once untrusted content can influence the model, the existence of a tool and the validity of its argument shape do not justify execution. Authorization must be re-applied to each concrete call, with concrete values, before side effects occur.