gcp-gcr-policy-set
storage.buckets.setIamPolicy on the GCR artifacts bucket = rewrite the registry IAM policy, enabling cross-project push grants, public pull, or access revocation.
match (effective permission)
{
"action": "storage.buckets.setIamPolicy",
"resource_type": "storage.googleapis.com/Bucket"
}
where
resource.name matches 'artifacts.<PROJECT>.appspot.com' (the GCR artifacts backing bucket, not an arbitrary GCS bucket)
emit
| source type | Identity |
|---|---|
| target type | ResourcePolicy |
| source | <principal with effective storage.buckets.setIamPolicy on the artifacts bucket> |
| target | <ResourcePolicy node for the artifacts.PROJECT.appspot.com bucket IAM policy> |
| permissions | storage.buckets.setIamPolicy |
| conditions | scp_or_org_policy |
| state logic | ACTIVE when the principal holds effective storage.buckets.setIamPolicy on artifacts.PROJECT.appspot.com. BLOCKED when a GCS IAM deny policy or org policy (constraints/iam.allowedPolicyMemberDomains) prevents the rewrite. CONDITIONAL(scp_or_org_policy) when org policy constraints limit which members can be granted roles on GCS resources in this project. |
Narrative
{principal.name} can set the IAM policy of the GCR artifacts bucket artifacts.{project.name}.appspot.com (storage.buckets.setIamPolicy). This allows granting push access to an external attacker (supply-chain backdoor), making images publicly pullable (credential exfil), or revoking access to disrupt workloads. The policy change takes effect immediately.
Raw rule rules/derived/gcp/gcr.yaml
id: gcp-gcr-policy-set
emits: CanModifyPolicy
description: storage.buckets.setIamPolicy on the GCR artifacts bucket = rewrite the registry IAM policy,
enabling cross-project push grants, public pull, or access revocation.
match_effective_permission:
action: storage.buckets.setIamPolicy
resource_type: storage.googleapis.com/Bucket
where:
- resource.name matches 'artifacts.<PROJECT>.appspot.com' (the GCR artifacts backing bucket, not an arbitrary
GCS bucket)
emit:
source_type: Identity
target_type: ResourcePolicy
source: <principal with effective storage.buckets.setIamPolicy on the artifacts bucket>
target: <ResourcePolicy node for the artifacts.PROJECT.appspot.com bucket IAM policy>
permissions:
- storage.buckets.setIamPolicy
conditions:
- scp_or_org_policy
state_logic: ACTIVE when the principal holds effective storage.buckets.setIamPolicy on artifacts.PROJECT.appspot.com.
BLOCKED when a GCS IAM deny policy or org policy (constraints/iam.allowedPolicyMemberDomains) prevents
the rewrite. CONDITIONAL(scp_or_org_policy) when org policy constraints limit which members can be
granted roles on GCS resources in this project.
confidence: 0.95
derived_from:
- effective storage.buckets.setIamPolicy on artifacts.<PROJECT>.appspot.com
false_positive_note: "storage.buckets.setIamPolicy at project level (roles/storage.admin at project)\
\ applies to ALL GCS buckets, not just the artifacts bucket. Scope the target of this CanModifyPolicy\
\ to the artifacts bucket's ResourcePolicy node only. Org policy constraints/iam.allowedPolicyMemberDomains\
\ can restrict the ability to add external members even with setIamPolicy \u2014 emit CONDITIONAL(scp_or_org_policy)\
\ when such a constraint is in effect. gcp/identity-escalation gcp-set-iam-policy-resource also fires\
\ for this permission; deduplicate on (CanModifyPolicy, principal, artifacts-bucket-policy) \u2014\
\ emit once."
narrative: '{principal.name} can set the IAM policy of the GCR artifacts bucket artifacts.{project.name}.appspot.com
(storage.buckets.setIamPolicy). This allows granting push access to an external attacker (supply-chain
backdoor), making images publicly pullable (credential exfil), or revoking access to disrupt workloads.
The policy change takes effect immediately.'