Identity Federation & Trust-Root Compromise
After this chapter you will be able to read a cloud trust policy the way an attacker does, recognise the four ways a federation relationship can be abused across AWS, Azure and GCP, and explain why a flaw at a trust root becomes a skeleton key that crosses every boundary the federation was built to span.
Imagine two organisations, each with its own way of knowing who its people are — its own staff directory, its own logins. One day they agree to cooperate: organisation A says "if organisation B's directory vouches for someone, we will treat that person as one of ours." That agreement is a piece of configuration, written once and then forgotten.
Now imagine you are at neither organisation. You get hold of the thing organisation B uses to vouch for people — or you simply notice that organisation A's agreement is sloppily worded and accepts a voucher from anyone, not just organisation B. Either way you can now hand organisation A a slip of paper that says "this person is trusted," and A will believe it. You did not steal a password. You did not break in. You forged, or borrowed, a voucher at the place where trust begins.
That is federation, and that is this chapter. When a cloud agrees to trust identities minted somewhere else, the agreement itself becomes the attack surface — and unlike a stolen password, a broken trust root opens every door at once.
The problem
Identity and Access Management — IAM — is the part of a cloud that decides, on every single API call, who you are and what you are allowed to do. It is the gatekeeper of the entire control plane, the subsystem that turns a request into either an action or an AccessDenied. The first half of that question — who you are — is rarely answered by the cloud alone. It is answered by federation.
Federation is the arrangement by which a cloud agrees to trust identities minted somewhere else: your corporate directory, a CI/CD system like GitHub Actions, a partner's tenant, or even another product from the same vendor. The cloud does not run the directory or issue the login; it merely accepts a signed token and treats whoever the token names as one of its own. That arrangement is configured as data — an identity-provider object plus a rule — and data can be misconfigured, or forged.
What goes wrong is rarely a broken cryptographic primitive or a buffer overflow. It is something subtler. A federation relationship reduces, underneath all the protocol grammar, to a single trust equation: a token signed by key K, satisfying condition C, is granted role R. Every federation flaw is a defect in one of those three terms — the condition C is missing or too loose, the key K is forgeable or stealable, or the validator that checks the equation is itself buggy. The trust the equation expresses is the whole attack surface.
And federation is built to cross boundaries. Its entire purpose is to collapse several identity systems into one trust root so a user signs in once and reaches everything. Compromise that root and you inherit the same property in reverse: one forged token crosses every boundary the federation was built to bridge. That is why this chapter treats trust roots, not in-tenant permission lists, as the centre of gravity.
Why this differs from a traditional pentest
A traditional pentest — and a single-tenant cloud pentest — escalates inside one account, and the blast radius is that one account. A federation flaw is a different kind of bug: it does not climb a privilege ladder, it hands you a valid identity at the trust root, and that identity is honoured by every system the federation bridges — every account, tenant and product downstream. It crosses boundaries by design; the forged token authenticates through the front door, so there is little to alert on; and when the flaw is in the IAM platform's own validator rather than a customer's configuration, no customer can be blamed and every tenant is exposed at once. Single-tenant pentesting never reaches that class.
Single-tenant IAM privilege escalation is real and well catalogued — Rhino Security Labs documents roughly 21 AWS and 17-plus GCP single-permission paths to administrator, things like iam:CreatePolicyVersion or iam.serviceAccountKeys.create. An attacker uses them as a building block: a small permission in one tenant is often what lets you reach a federated credential or mint a token in the first place. But in-tenant privesc stays inside one account and has no provider angle, so this chapter treats it as out of scope as headline material and focuses on the trust roots that cross boundaries.
You arrive holding Chapter 2's map: you have enumerated identities, roles and trust relationships in the target. Before the climb, one skill has to be in your bones — reading a trust policy.
Reading a trust policy as an attacker
A cloud expresses "who is allowed to become or use this thing" in a trust policy (AWS calls it a resource policy; on an IAM role it is a separate document, the AssumeRolePolicyDocument). Unlike a permission policy, a trust policy grants no actions at all — it answers only the identity question. But before reading one, you need a concrete picture of where it lives and who writes it — because that picture is exactly what the rest of the chapter exploits.
Take an ordinary situation. A company owns an AWS account and runs its CI/CD on GitHub Actions. It wants that pipeline to deploy into the account — but it does not want a long-lived AWS access key stored in GitHub, where a single leak would be catastrophic. So it sets up federation, and it does the entire setup on its own side, inside its own AWS account:
- It registers GitHub as an OIDC identity provider — an IAM identity-provider object that records "tokens issued by
token.actions.githubusercontent.comcome from an issuer we recognise." - It creates an IAM role holding the permissions the pipeline needs, and attaches a trust policy to that role saying which GitHub tokens are allowed to assume it.
Notice who does what. The AWS account owner — the company — performs every step above and writes the trust policy; the external party never "logs in to AWS" and configures nothing on the AWS side. The external party (here GitHub) does exactly one thing: when a workflow runs, it mints and signs a short-lived token naming the repository that ran. That external party is often a third-party vendor like GitHub, but it can equally be the company's own corporate directory (ADFS, Okta, Entra) or another cloud — anything that issues identities the cloud's own IAM did not. The trust policy is the company's standing instruction for which of those externally-minted tokens to honour. Here is a correctly written, fully scoped trust policy for that role — the standard the rest of this chapter will show attackers departing from:
Allows or Denys. Allow means: if every condition below is satisfied, let the caller assume this role."Federated" means the trusted party is an external identity provider, not an AWS account. The ARN points at the OIDC-provider object the account registered for GitHub: 111122223333 is the role owner's own account, and the rest is GitHub's issuer. This is key K — whose signature AWS will trust.AssumeRoleWithWebIdentity, the STS call that swaps a GitHub-signed OIDC token for temporary AWS credentials. SAML federation uses AssumeRoleWithSAML instead.Condition means no scoping at all.aud (audience) claim — which service the token was minted for. Every GitHub OIDC token meant for AWS carries sts.amazonaws.com, so this check alone proves only "a GitHub token for AWS" — not which repository sent it. Necessary, but nowhere near sufficient on its own.sub (subject) claim — which repository, branch or workload the token represents. This is the line that actually scopes the trust: only tokens from acme-corp/deploy-pipeline on the main branch are accepted. A correct federated trust policy must pin sub (or an equivalent claim). Remember this line — T1 shows exactly what happens when it is missing.Hover (or tap) each numbered marker for a line-by-line explanation.
Read it against the story. The document is attached to the company's role — that role is the equation's R. Principal names the external party: in arn:aws:iam::111122223333:oidc-provider/token.actions.githubusercontent.com, account 111122223333 is the company's own account, and the rest identifies the GitHub OIDC-provider object it registered in step 1 — this is the key K, the issuer whose signature will be trusted. Condition is term C, the scope — and here it does its job: the sub line pins the trust to one repository on one branch, so only the company's own pipeline qualifies. And the attacker is a fourth party: someone at neither the company nor GitHub, who either holds a GitHub-signed token from their own repository, or — far more commonly — finds a copy of this policy where that scoping sub line was never written. The whole of this chapter is what happens when this document is wrong.
So three fields carry the weight. Effect is Allow or Deny. The keyword "Federated" inside Principal is the tell that the trusted party is an external identity provider rather than an AWS account. And the Condition is where the security actually lives. An OIDC token carries claims — among them aud (the audience: which service the token was minted for) and sub (the subject: which repository or workload the token represents). The policy above is correctly scoped: it checks aud and, decisively, sub — the claim that pins the trust to one specific repository. A federation flaw is what you get when this document is written wrong; the most common mistake is a Condition that omits the sub line and so accepts any validly signed token. T1 takes exactly that mistake apart.
Federated principal and STS ▾A Principal of {"Federated": …} points at an IAM identity-provider object — the SAML or OIDC provider the account registered. The matching STS calls are AssumeRoleWithSAML and AssumeRoleWithWebIdentity: present a token the provider signed, satisfy the Condition, and STS returns short-lived credentials (an access key id beginning ASIA).
So a federated role is reachable by anyone who can produce a token that key K will sign and condition C will accept — no AWS account membership required.
The methods at a glance
Every technique in this chapter is an attack on one of the three terms of the trust equation. There are four to learn; they are transferable across AWS, Azure and GCP, and a federation feature launched next year will fall into one of them.
| Technique | Which term of the equation it breaks | Representative case |
|---|---|---|
| T1 · Missing-condition federation | Condition C is absent — any validly signed token is accepted. | GitHub-Actions-to-AWS OIDC, no sub check |
| T2 · Forgeable-key federation | Key K is stolen — the attacker signs their own valid tokens. | Golden SAML — stolen ADFS token-signing key |
| T3 · Federation backdooring | The attacker adds a new K — a credential or a rogue trust root. | Entra service-principal credential / rogue federated domain |
| T4 · Cross-product federation abuse | One product's trust is honoured by another product entirely. | Google Workspace domain-wide delegation |
Defenders and tooling fixate on who holds AdministratorAccess, Owner or Global Administrator. Federation makes that the wrong search: a federation flaw never appears in a permission report, because it grants nobody a permission — it lets an outsider become a principal that already has the permission. Audit the identity-provider objects, the signing keys and the trust policies, not the role list.
The next four sections take one technique each — what it is, how it works, and a real-world illustration.
T1 — Missing-condition federation: GitHub OIDC any-repo assumption
What it is. The most common federation flaw in modern cloud estates is a trust policy that omits its Condition — or whose condition checks only a value every token already carries. The relationship is genuine; it is simply scoped to everyone.
How it works. The textbook case is GitHub-Actions-to-AWS OIDC, the keyless way for a CI pipeline to obtain AWS credentials. You saw a correctly written version in the previous section — its Condition pinned the sub claim to one repository. The vulnerable version is almost identical; here is the Condition as attackers routinely find it:
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
}
}
Set this side by side with the correct policy and the entire vulnerability is one missing line — the sub condition is simply gone. What remains, aud, only proves the token was minted for AWS STS, and every GitHub repository's OIDC token carries that same audience. So the trust policy now says, in effect, "any validly signed GitHub OIDC token is welcome" — meaning any GitHub repository on the internet can assume the role. Term C of the trust equation has collapsed to "true."
Datadog Security Labs ran a Sourcegraph regex over public .github/workflows/ files and harvested 500-plus role ARNs across 275-plus AWS accounts configured for GitHub OIDC; a meaningful share had trust policies with no sub condition.[1]#153 The technique, run from any GitHub Action in any repository:
- Inside any GitHub Action, request the OIDC JWT for the AWS audience:
curl -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=sts.amazonaws.com" - Exchange it for credentials in the victim account:
aws sts assume-role-with-web-identity --role-arn <target> --role-session-name s --web-identity-token file://jwt - If the trust policy checks only
aud, STS returnsASIA…credentials — the response even echoesSubjectFromWebIdentityToken, naming the attacker's repository.
In one real case, the UK Government's alphagov org had a role, github_action_mirror_repos_role, granting codecommit:GitPull/GitPush on Resource: "*" and missing the sub condition. Researchers assumed it from an arbitrary, unrelated repository and could read — and could have silently backdoored — every private CodeCommit mirror in the account. This is a genuine cross-tenant break: an attacker in their own GitHub repository reached straight into a stranger's AWS account.
sts:AssumeRoleWithWebIdentity returns live ASIA… credentials. The SubjectFromWebIdentityToken field shows the request came from an arbitrary repo — the trust policy never checked. Source: [1]#153Real-world illustration. The same shape recurs wherever a cloud trusts an external IdP and the operator forgets to scope it: an Azure workload-identity federation that names an issuer but no subject, a SAML role whose only condition is the IdP name. Whenever you see a Federated principal, your first move is to read the Condition — and an absent one is an open door.
T2 — Forgeable-key federation: Golden SAML
What it is. A deeper failure than a missing condition is a compromised key K. If an attacker can sign tokens with the identity provider's own key, no condition saves the relationship — every token they mint is, by definition, valid. The validator is doing its job perfectly; it is just being shown genuine forgeries.
How it works. A SAML service provider — AWS, vSphere, an Azure app — trusts any assertion bearing a valid signature from the IdP's token-signing private key. Steal that key and you can author assertions naming any user with any role.
CyberArk Labs named Golden SAML after the Kerberos golden ticket: it forges authentication at the trust root rather than stealing a credential at the leaves.[2]#053
- Compromise the ADFS service account (a far lower bar than Domain Admin); export the token-signing private key and the IdP public certificate, e.g. with Mimikatz.
- Gather the rest of the inputs — IdP name, target role ARN, AWS account id, a
Domain\usernameto impersonate. - Run
shimit: it builds a SAML assertion naming any user with any role, signs it with the stolen key, and callssts:AssumeRoleWithSAML. - AWS STS validates the signature — it is genuine — and returns temporary credentials, written straight into the CLI environment.
The persistence is what makes it feared: it survives password changes, works straight through 2FA, the signing key is not auto-rotated, and the forgery can be generated from anywhere. The authors stress it is "not a vulnerability in SAML or AWS" — it is trust working exactly as designed once the key is stolen. There is nothing to patch; defend it at the key, or not at all.
Real-world illustration. Golden SAML is a control-plane intrusion technique, not a one-account trick: a single stolen ADFS key signs assertions for every service provider that trusts that IdP — AWS, Microsoft 365, internal apps — so one key compromise crosses the entire federation in one move. It was a documented component of large supply-chain intrusions where attackers forged their way into cloud tenants without ever touching a password.
T3 — Federation backdooring: adding your own trust root
What it is. T2 steals an existing key. T3 is subtler and quieter: rather than steal key K, the attacker adds a new one — a fresh credential on a trusted identity, or an entirely new federated domain — so the tenant now trusts something the attacker controls. It is failure mode 2 achieved without breaking any cryptography, just by writing configuration.
Entra splits an "application" into two objects: an app registration is the global definition (its API permissions, its appId); a service principal is the local instance of that app inside one tenant — the thing that holds role assignments and can sign in.
Credentials live on the service principal, and adding one lets you authenticate as that application — which is what makes service-principal backdooring possible: you do not modify the global app, you quietly add a key to its local instance.
How it works. In Entra, a service principal with the right Microsoft Graph permission can do two backdoor moves. First, add a keyCredential (a client secret or certificate) to a privileged service principal and then authenticate as that application. Second — more powerful — add a brand-new federated domain to the tenant: its own trust root, its own signing certificate, after which the attacker can forge SAML tokens for any synced user, including Global Admins.
Datadog Security Labs showed this through the built-in Office 365 Exchange Online first-party service principal, which lacked the app-instance property lock that protected other first-party apps.[3]#169 Adding a credential to that service principal yielded the application's privileges, and from there the path led to Global Administrator. Because keyCredentials are stored separately on the app registration and on the service principal, a key added to the service principal is invisible to anyone auditing only the app registration — a backdoor that hides in the seam between two objects.
keyCredentials are stored separately on each — so a key added to the service principal is invisible to anyone auditing only the app registration. Source: [3]#169Real-world illustration. The rogue-federated-domain variant is a favourite for durable persistence: once the attacker's own signing certificate is registered as a trusted domain, they can forge a token for any user at will, indefinitely, with nothing stored in the victim's normal credential surface to rotate away. It is the federation equivalent of the cross-account backdoor — access that survives password resets and key rotations because the trust itself was rewritten.
T4 — Cross-product federation abuse: Workspace domain-wide delegation
What it is. Federation does not only bridge an external directory to a cloud — it can bridge one product to another inside the same vendor. When it does, a modest permission in product A becomes an enormous capability in product B, and the two are governed and logged separately.
Domain-wide delegation lets a Google Workspace super-admin authorise a GCP service account to impersonate any Workspace user in the organisation, bounded only by a set of OAuth scopes such as gmail.readonly or drive. The GCP service account becomes a federated identity into the entire Workspace tenant.
How it works. The delegation links a GCP-plane object (the service account) to a Workspace-plane capability (impersonate any user). So anyone who can act as that service account inherits the delegation — and acting as a GCP service account is a routine GCP-plane operation, governed by ordinary GCP IAM.
Unit 42 spelled out the consequence.[4]#116 Picture a GCP project containing a delegated service account. Any GCP identity that can mint a token for that service account — via iam.serviceAccounts.getAccessToken, or a stolen JSON key — can call the Workspace token endpoint with the service account's client id and a sub of any employee, and then read that person's Gmail, Drive and Docs.
A modest GCP-plane permission, an enormous Workspace-plane impact. And detecting it requires logs from both products, correlated — the GCP audit log shows a token mint, the Workspace log shows a data access, and neither alone looks like an attack.
Real-world illustration. This is the cross-product pattern in general: a CI system federated into a cloud, a cloud service account delegated into a SaaS suite, one tenant's app trusted by another tenant's directory. The lesson is the same each time — trace where a federation grant is honoured, not just where it is configured, because the impact lands wherever the trust is consumed.
T1–T4 all depend on a customer misconfiguration or a stolen secret. A worse class exists: a flaw in the IAM platform's own trust validator, requiring no misconfiguration and with a blast radius of every tenant the platform serves. The 2025 Entra ID Actor-token bug (CVE-2025-55241) — where a token minted in an attacker's own tenant authenticated as Global Admin in any other tenant — is the flagship example.[5]#246 It breaks the third term of the trust equation, the validator itself. Because that is a cross-tenant, provider-side break rather than a federation primitive, it is dissected in Chapter 11; treat this note as the pointer to where provider-side federation flaws are covered.
Attacker's checklist
- Enumerate the trust roots first: IAM identity-provider objects, OIDC providers, SAML providers, Entra federated domains, Workspace domain-wide-delegation grants.
- For every federated role, read the
Condition. A missingsub/subjectcondition, or one that checks only an audience claim, is an open door — assume the role from your own repository or IdP. - For SAML trust, locate the token-signing key. Compromising the IdP service account (not Domain Admin) is enough to forge assertions for every service provider that trusts it.
- Look for backdooring opportunities: can you add a
keyCredentialto a privileged service principal, or register a new federated domain? Both give you a trust root the tenant now honours. - Trace cross-product federation: a GCP service account delegated into Workspace, a CI identity federated into a cloud. Ask what a modest permission in product A becomes in product B.
- For persistence, prefer a rogue federated domain or an added signing key over a stored credential — there is nothing in the victim's normal credential surface to rotate away.
- In-tenant privilege escalation (the 21 AWS / 17 GCP single-permission methods) is your building block — use it to reach a federated credential or token-mint permission, not as the objective.
Defender's mirror
A federation flaw rarely appears in a permission report, but the surrounding intrusion still leaves fingerprints. Datadog's "unwanted visitor" case is the canonical example: an attacker with a stolen AKIA key called sts:GetFederationToken with an inline {"Action":"*","Resource":"*"} policy to pivot from CLI to console, then created an IAM role named SupportAWS whose trust policy was "Principal": {"AWS": "713521355166"} — the attacker's own AWS account, with an empty Condition — and attached AdministratorAccess to it.[6]#158 That is a cross-account backdoor role: a trust relationship rewritten to point at the attacker, durable access with no stored credential in the victim account, and a legitimate-sounding name. It is T3 in miniature — the defender's job is to notice the trust policy changed.
- Trust policies are the perimeter. Require a
sub/subjectcondition on every OIDC and SAML federated role; requireaws:SourceArn/aws:SourceAccountor external-id conditions on every cross-account role. - Alert on trust-root changes. Every
iam:UpdateAssumeRolePolicy, every new IAM identity provider, every new Entra federated domain, everykeyCredentialadded to a service principal, every new domain-wide-delegation grant — these are rare and high-signal. - Protect the signing keys. Auto-rotate SAML token-signing keys; treat the ADFS / IdP service account as Tier-0; apply the app-instance property lock to privileged first-party applications so a credential cannot simply be added.
- Correlate across products. Cross-product abuse is invisible in any single log. Wire GCP service-account token mints to Workspace data-access events; wire CI OIDC assumptions to the repositories that should own them.
- The hard truth. A token forged at the trust root authenticates as a legitimate user through the front door. The reliably observable moments are the trust-root mutation and the first appearance of an unexpected federated principal — build detection there, not around reconnaissance.
- Federation is a cloud trusting identities minted elsewhere. Every federation relationship reduces to one trust equation: a token signed by key K, satisfying condition C, is granted role R.
- Read the trust policy, not the permission list: the
Federatedprincipal is the key K, theConditionis C — a federation flaw grants nobody a permission, it lets an outsider become a principal that already has one. - Four techniques: missing condition (GitHub OIDC), forgeable key (Golden SAML), federation backdooring (Entra service principal / rogue domain), and cross-product abuse (Workspace domain-wide delegation).
- A federation flaw is a skeleton key, not a ladder: it crosses every boundary the federation was built to bridge, including provider-side platform bugs no customer can be blamed for.
- In-tenant privilege escalation exists and is a useful building block, but it stays inside one account and has no provider angle — the trust roots are where cross-boundary impact lives.
- When the IAM platform's own validator is the bug, no customer can be blamed and the blast radius is every tenant; that provider-side class is Chapter 11's subject.
References
- Christophe Tafani-Dereeper, Datadog Security Labs, "Exploring GitHub-to-AWS keyless authentication flaws via OIDC". Archived: local copy · Original: securitylabs.datadoghq.com. Corpus #153.
- Shaked Reiner, CyberArk Labs, "Golden SAML: Newly Discovered Attack Technique Forges Authentication to Cloud Apps". Archived: local copy · Original: cyberark.com. Corpus #053.
- Katie Knowles, Datadog Security Labs, "I SPy: Escalating to Entra ID Global Admin with a first-party application". Archived: local copy · Original: securitylabs.datadoghq.com. Corpus #169.
- Zohar Zigdon, Unit 42 (Palo Alto Networks), "Exploring a Critical Risk in Google Workspace's Domain-Wide Delegation Feature". Archived: local copy · Original: unit42.paloaltonetworks.com. Corpus #116.
- Dirk-jan Mollema, Outsider Security, "Obtaining Global Admin in every Entra ID tenant with Actor tokens" (CVE-2025-55241). Archived: local copy · Original: dirkjanm.io · also cloudvulndb.org. Corpus #246.
- Oren Margalit, Datadog Security Labs, "Tales from the cloud trenches: unwanted visitor". Archived: local copy · Original: securitylabs.datadoghq.com. Corpus #158.