gcp-wif-modify-trust-provider
Creating or updating a WIF pool provider lets a principal add/loosen the trust to an attacker-controlled external IdP.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
?principal has EFFECTIVE iam.workloadIdentityPoolProviders.update OR .create (or iam.workloadIdentityPools.update/.create) on ?pool / its project
node_type(?pool) ==
TrustPolicy # Workload Identity Pool provider trust config
emit
| source type | Identity |
|---|---|
| target type | TrustPolicy |
| source | ?principal |
| target | ?pool |
| permissions | iam.workloadIdentityPoolProviders.create iam.workloadIdentityPoolProviders.update iam.workloadIdentityPools.create iam.workloadIdentityPools.update |
| conditions | iam_permission |
| state logic | ACTIVE for the trust-write capability when the principal has the effective create/update permission at the pool/project scope and no deny policy denies it. Note this is the CONFIG-side capability: it becomes a federation only once the principal (or an IdP it controls) presents a matching token AND an SA carries a workloadIdentityUser binding for the (now-loosened) provider — chain via rule 1. BLOCKED if an IAM deny policy or org policy (e.g. iam.workloadIdentityPoolProviders allowed-issuer constraint) denies the write. |
Narrative
{principal.name} can create or update the workload identity pool provider {pool.name} (iam.workloadIdentityPoolProviders.create/.update) to trust an attacker-controlled IdP or loosen its issuer/audience/attribute condition, making an external identity it controls acceptable.
Raw rule rules/derived/gcp/wif.yaml
id: gcp-wif-modify-trust-provider
emits: CanModifyTrust
description: Creating or updating a WIF pool provider lets a principal add/loosen the trust to an attacker-controlled
external IdP.
applies_to:
- gcp
match:
- - principal: null
- CanControl
- pool: null
where:
- ?principal has EFFECTIVE iam.workloadIdentityPoolProviders.update OR .create (or iam.workloadIdentityPools.update/.create)
on ?pool / its project
- 'node_type(?pool) == TrustPolicy # Workload Identity Pool provider trust config'
emit:
source_type: Identity
target_type: TrustPolicy
source: ?principal
target: ?pool
permissions:
- iam.workloadIdentityPoolProviders.create
- iam.workloadIdentityPoolProviders.update
- iam.workloadIdentityPools.create
- iam.workloadIdentityPools.update
conditions:
- iam_permission
state_logic: "ACTIVE for the trust-write capability when the principal has the effective create/update\
\ permission at the pool/project scope and no deny policy denies it. Note this is the CONFIG-side\
\ capability: it becomes a federation only once the principal (or an IdP it controls) presents a matching\
\ token AND an SA carries a workloadIdentityUser binding for the (now-loosened) provider \u2014 chain\
\ via rule 1. BLOCKED if an IAM deny policy or org policy (e.g. iam.workloadIdentityPoolProviders\
\ allowed-issuer constraint) denies the write."
confidence: min(contributing_confidences) * 0.95
derived_from:
- ?principal effective iam.workloadIdentityPoolProviders.update/.create on ?pool
false_positive_note: "This is a config-side PRIVESC PRIMITIVE, not a realized takeover by itself: adding/loosening\
\ a provider only yields access when combined with an SA workloadIdentityUser binding an attacker-controlled\
\ subject can satisfy (rule 1). An org policy constraint restricting allowed issuers (constraints/iam.workloadIdentityPoolProviders.allowedIssuers\
\ or an allowedAudiences constraint) narrows or BLOCKS the loosening \u2014 honor it. Do not emit\
\ ACTIVE if the principal only has read (.get/.list) on the pool."
narrative: '{principal.name} can create or update the workload identity pool provider {pool.name} (iam.workloadIdentityPoolProviders.create/.update)
to trust an attacker-controlled IdP or loosen its issuer/audience/attribute condition, making an external
identity it controls acceptable.'