An IAM OIDC provider trusts tokens signed by an external issuer. A role tied to it is assumed with sts:AssumeRoleWithWebIdentity, and the only thing standing between an attacker and the role is the trust policy's Condition block on the token's sub (subject) and aud (audience) claims. If those are absent or wildcarded, any token the issuer will mint, including for an identity the attacker controls, assumes the role.
Assuming with a web-identity token#
aws sts assume-role-with-web-identity \
--role-arn arn:aws:iam::<acct>:role/<role> \
--role-session-name s \
--web-identity-token "$OIDC_JWT" --query Credentials
Reading the trust condition#
aws iam get-role --role-name <r> --query 'Role.AssumeRolePolicyDocument'
# look for the OIDC provider as Principal.Federated and the StringEquals/StringLike
# conditions on "<issuer>:sub" and "<issuer>:aud"
A trust with StringLike and a * in sub, or no sub condition at all, is assumable by any subject the issuer serves.
Exploitation notes#
- The audience check is only as strong as the
audcondition; a missingaudlets a token minted for a different application through. - For managed issuers you do not control, you still win when the
subcondition is loose enough to match an identity you can obtain from that issuer. - GitHub Actions is the most common concrete case and has its own page.
Tools#
- AWS CLI (
sts assume-role-with-web-identity): the assumption. - jwt_tool: inspect and craft the claims in a web-identity JWT.