Why authority narrows at every hop
The problem
Traditional application security assumes the call graph is written by a developer and fixed at
deploy time. An agentic system breaks that assumption: the model chooses the call graph at
inference time, and without something actively narrowing it, whatever hop 1 can do, hop 4
inherits unchanged. A user consents to check_bank_balance; four delegations later, nothing
structurally distinguishes that call from terminate_account unless something in between
refuses to let authority travel unmodified.
The rejected alternative: system-prompt rules
The obvious first fix — "tell the agent not to do that" in a system prompt — fails for a specific reason, not a vague one: a prompt rule is advisory text the model reads, and the same prompt-injection channel that attacks the agent can also attack the rule. Defending against injected instructions with an instruction is defending with the thing being attacked.
The design: RFC 8693 downscoping, derived hop depth
Every hop presents the token it was given and gets back a new, narrower token — never the same one forwarded. Two properties make this a structural narrowing rather than a checked policy:
- The exchanged token is bound to one target (
aud) and one data class (scope). Presenting it anywhere else fails audience validation outright; there is no code path where a token "still works" against a different resource. - Hop depth is derived from the token's verified
actchain, never accepted as a caller-supplied number. A four-hop chain produces a token withact: {sub: hop3, act: {sub: hop2, act: {sub: hop1}}}— nested proof of exactly how authority got here, not a claim anyone could assert. See Token Exchange Service for the exact exchange sequence.
The hop_budget declared in the manifest is enforced against this derived depth, so
"unbounded delegation" (PRD problem statement) becomes a hard ceiling rather than a convention:
allowed exactly at the budget, refused the hop after (HOP_BUDGET_EXCEEDED, not recoverable).
What this buys, concretely
Presenting a hop-2 token while claiming to be hop-3's agent is a deny — the token was issued
to a specific holder, and the caller must be whoever holds it. There is no "trusted broadly,
checked occasionally" middle state: every dispatch goes through the same narrow-then-verify
path, including the PDP's edge, scope, and budget checks.
Where to see it work
- Enroll your first agent gets you one hop's worth of this.
- Deploy the sidecar PEP shows the narrowing enforced on a real forwarded call, with nothing reaching the upstream on a deny.
- Reference →
POST /v1/token/exchangehas the exact request/ response shape.