Skip to content
Start with Identity
SWI-T012 · Authorization

Scope escalation through delegation

A chain of services each meant to narrow a token's authority instead widens it, because one hop in the delegation path trusts the scope a caller claims rather than the scope it was actually issued.

EmergingHard to detect
First observed: 2021

How it works

Scope escalation through delegation happens when a service that is supposed to pass on a narrower slice of a user's authority instead obtains, or accepts, a wider one. The resulting token carries more scope or audience than the delegation allowed, and nothing downstream can tell.

Modern architectures pass identity through several hops: a front end calls an API on the user's behalf, which calls another service. Token exchange (RFC 8693) and vendor equivalents such as the Microsoft identity platform's on-behalf-of (OBO) flow let each hop swap its token for one scoped to the next call. A typical escalation:

  1. A middle tier receives a user token for its own audience.
  2. It calls the token endpoint with that token as the subject (RFC 8693 subject_token, or the OBO assertion) and a scope or audience parameter for the downstream API.
  3. The issuer applies whatever policy it has. RFC 8693 says the meaning of scope is service specific and that a token is issued only if the request "meets all policy and other criteria of the authorization server". The RFC does not define that policy.
  4. If the policy allows widening, the new token is wider. Keycloak's documentation for its standard token exchange, which became officially supported in Keycloak 26.2 in 2025, states that by default exchange "can be used to request extra scopes and audiences". Restricting exchange to downscoping takes an explicit client policy (the downscope-assertion-grant-enforcer executor).
  5. Downstream services trust the result. RFC 8693 says a consumer MUST consider only the token's top-level claims and the current actor, and that prior actors in nested act claims are informational only. The resource server sees a valid, broad token and nothing of the chain.

The same failure appears without a token endpoint: a broker that forwards the caller's token (the Model Context Protocol calls this "token passthrough" and forbids it), or a proxy that trusts the scopes in a token without its own authorization check. A compromised hop, including an AI agent's tool server, can then reach further than its position allows.

Why it works

The control assumption that fails is that narrowing is a property of the protocol. It is a property of each issuer's policy and each service's checks. OAuth defines how to ask for a token on someone's behalf but leaves what a caller may ask for to each deployment, so a chain is only as narrow as its most permissive hop.

Three design facts make the gap easy to miss:

  • Defaults favour working over narrow. Microsoft's OBO documentation notes that a .default scope requests "all the scopes that the application has permissions for", and that preAuthorizedApplications can receive scopes in an OBO flow "without the user providing consent". A middle tier with broad permissions passes them on.
  • The issuer cannot see intent. A request to widen looks the same as a request to narrow. Only a per-client allowlist can tell them apart.
  • Exchanged tokens live in the MFA blind zone. Service-to-service exchange has no interactive sign-in, so MFA and most user-focused Conditional Access policies never see it.

CVE-2025-55241 showed how far an unchecked delegation primitive can reach. Dirk-jan Mollema found that undocumented Entra "Actor tokens", used by Microsoft services to act for users, were wrapped in an unsigned impersonation token that the legacy Azure AD Graph API accepted without validating the originating tenant, letting one tenant impersonate any user, including Global Admins, in another. He reported the tokens were valid for 24 hours, unlogged at issuance, and bypassed Conditional Access. Microsoft fixed it on July 17, 2025, three days after the report. CVE-2025-14778 is a smaller instance: Keycloak's UMA policy evaluation checked only the first requested resource.

How to detect it

  • Entra sign-in logs: isolate delegation flows. In Microsoft Graph's beta signIn resource, authenticationProtocol includes the values onBehalfOf and samlOnBehalfOf. Baseline which appId values use OBO and which resourceId targets they request, then alert on a new pairing.
  • Entra sign-in logs: partner and cross-tenant access. crossTenantAccessType = serviceProvider marks cross-tenant access by a service provider (partner). Microsoft's 2021 Nobelium guidance was to filter non-interactive sign-ins on that value to see partner activity in a tenant.
  • Okta System Log. In Okta, app.oauth2.as.token.grant.interclient_token records a token issued through OAuth token exchange, and app.oauth2.as.token.grant.access_token records the client, subject, grant type and token attributes.
  • Your own token service. RFC 8693 requires the response to include scope whenever the issued scope differs from the requested scope. Log requested and granted scope and audience for every exchange, as the MCP security guidance also recommends.
  • Impersonated writes. For Actor tokens, Mollema found reads left no logs, but writes logged the impersonated user's UPN with the Exchange display name.

Be honest about the limits: a new scope is often a new feature, many teams do not log exchange decisions, and without a per-service baseline the signal is noise. The worst case, Actor tokens, produced no read logs in the victim tenant at all.

How to stop it

  1. Allowlist scopes and audiences per client at the issuer. A caller should never receive more than its registered policy permits, whatever it asks for. In Keycloak, apply the downscope enforcer through Client Policies and enable the "Standard token exchange" switch only on clients that need it.
  2. Never pass tokens through. Services MUST NOT accept tokens not issued for them (the MCP rule), and middle tiers must reject a token whose aud is another app. Microsoft's OBO flow enforces this at the token endpoint.
  3. Bind tokens to one resource. Use resource indicators (RFC 8707) so a token for one API is useless at another, and consider OAuth Transaction Tokens for internal call chains so the edge token never travels.
  4. Scope partner and admin delegation. Replace broad delegated admin with Microsoft's granular, time-bound GDAP roles, and remove relationships that are no longer in use.
  5. Authorize every hop, not just the first. Apply least privilege and privilege escalation review to the whole delegation chain. The guide to securing AI agent identities covers agent and tool-server hops.
  6. Keep exchanged tokens short-lived. RFC 8693's security considerations suggest scope plus a limited lifetime to reduce delegation abuse. That limits the window, not the breadth.

Seen in the wild

No public breach in our catalog has been attributed to a token exchange endpoint widening scope by name. The closest attributed incident is delegation that was broader than the job required:

Sources

Last reviewed By SWI Community TeamSuggest a correctionHow we research
Seeing this technique used differently, or have a detection rule that works better? Email community@startwithidentity.com. See all briefs in the technique catalog, or volunteer as a CVE Analyst.
Mapped to MITRE ATT&CK where a technique ID exists. Independent, community-driven analysis, not a substitute for the ATT&CK knowledge base. See the disclaimer.