GitHub Actions can authenticate to AWS through the GitHub OIDC provider, assuming a role with sts:AssumeRoleWithWebIdentity and no stored secret. The role's trust policy is meant to pin the token's sub claim to a specific repo:org/name:.... When that condition is wildcarded or scoped only to the org, a workflow in any matching repository, including a fork or a repo you create, assumes the role.
The loose trust#
aws iam get-role --role-name <role> --query 'Role.AssumeRolePolicyDocument'
# look for token.actions.githubusercontent.com:sub with StringLike "repo:org/*"
# or a condition on :aud only, with no :sub pin
A sub like repo:org/*:ref:refs/heads/* accepts any branch of any repo in the org; a missing sub accepts any repo GitHub will mint a token for.
Assuming from a workflow#
A workflow you control in a matching repo requests the OIDC token and assumes:
permissions: { id-token: write }
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::<acct>:role/<role>
aws-region: us-east-1
Exploitation notes#
- Org-only scoping is the common mistake: a public org lets outsiders open a repo that satisfies
repo:org/*. - The
audclaim alone is not a scope; without asubcondition any token the provider issues is accepted. - See OIDC for the general web-identity mechanics behind this.
Tools#
- aws-actions/configure-aws-credentials: the standard assumption action.
- AWS CLI (
sts assume-role-with-web-identity) with a token obtained from the Actions runtime.