The cloud industry is aggressively moving away from long-lived secrets like static service account keys. These permanent credentials pose a massive security liability: they are easily leaked, difficult to rotate at scale, and often retain excessive privileges indefinitely.
While mechanisms exist to allow keyless authentication for workloads, misconfiguring them can allow unauthorized actors to gain access to your cloud resources - an attack known as the Confused Deputy Attack.
While WIF is robust, it introduces a critical risk when used with public, multi-tenant IdPs. The OIDC token issuer is shared across all GitHub users, not just your organization.
If your cloud policy trusts the issuer generally but fails to validate specific attributes (like the repository), you are vulnerable to a Confused Deputy attack:
Under that scenario, the cloud gets confused. It blindly trusts the token issuer without verifying the specific token owner. Consequently, the cloud, acting as the “deputy”, unwittingly misuses its authority to issue keys for your resources in order to help an attacker.
Google warns about this explicitly in their documentation:
Warning: GitHub, GitLab SaaS, and Terraform Cloud use a single issuer URL across all organizations… To help protect against spoofing threats, you must use an attribute condition that restricts access to tokens issued by your GitHub organization…
To prevent this, you must enforce strict attribute conditions within your Workload Identity Pool Provider. Never rely solely on the issuer URL.
Map and validate specific claims to ensure the token originates from your environment. Use the following attribute condition to restrict access to your specific GitHub organization:
assertion.repository_owner=='ORGANIZATION'
Replace ORGANIZATION with the name of your GitHub organization.
For tighter security, limit access to specific branches or workflows. The following condition ensures the token is only valid if generated from the main branch:
assertion.repository_owner=='ORGANIZATION' && assertion.ref=='refs/heads/main'
By implementing these conditions, even if an attacker presents a valid token from the correct issuer, Google Cloud will reject the request because the repository_owner claim will not match your policy.
In AWS, mitigation is handled via the Trust Policy attached to the IAM Role. You must add a Condition block that validates the sub (Subject) claim of the incoming OIDC token. This recommendation also appears in AWS’s documentation.
Modify the IAM Role’s Trust Relationship to include a StringLike or StringEquals condition. This ensures the token was issued for your repository, not just any repository on GitHub.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:ORGANIZATION/REPOSITORY:*"
},
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
}
}
}
]
}
sub: The subject claim. Format is repo:<org>/<repo>:<filter>.aud: The audience claim. Always validate this matches sts.amazonaws.com (or your custom audience) to prevent token replay from other services.To lock the role down to a specific branch (e.g., main), tighten the sub condition:
"StringEquals": {
"token.actions.githubusercontent.com:sub": "repo:ORGANIZATION/REPOSITORY:ref:refs/heads/main"
}
By implementing these conditions, even if an attacker presents a valid token from the correct issuer, AWS will reject the AssumeRole request because the sub claim will not match your trust policy.