Skip to content

GCP_ROLE_SCOPED_TO

Copy page

Summary

Forestall ACL Alias GCP_ROLE_SCOPED_TO
GCP Alias Entity Relation (Structural)
Affected Object Types Organizations, Folders, Projects
Exploitation Certainty Certain

Description

GCP_ROLE_SCOPED_TO is a structural edge connecting an IAM role binding to the GCP resource it is scoped to. In GCP, every IAM role assignment has three components: a principal (who), a role (what), and a resource (where). This edge represents the “where” — the resource scope of the binding.

Understanding scope is critical for assessing the blast radius of a role assignment:

  • A binding scoped to an organization grants the role across every folder, project, and service account in the organization.
  • A binding scoped to a folder grants the role across every project and service account in that folder and all its subfolders.
  • A binding scoped to a project grants the role only within that project.

The GCP_ROLE_SCOPED_TO edge enables scope-aware attack path traversal: an attack path that starts at an org-scoped binding fans out to affect every resource in the entire hierarchy, whereas a project-scoped binding affects only that single project.

Identification

gcloud CLI

# Get all role bindings at org scope
ORG_ID=$(gcloud organizations list --format="value(name)" | head -1)
gcloud organizations get-iam-policy $ORG_ID --format=json | \
jq '.bindings[] | {scope: "organization", role: .role, members: .members}'
# Get all role bindings at folder scope
FOLDER_ID="folders/123456789"
gcloud resource-manager folders get-iam-policy $FOLDER_ID --format=json | \
jq '.bindings[] | {scope: "folder", role: .role, members: .members}'
# Get all role bindings at project scope
PROJECT_ID="my-project"
gcloud projects get-iam-policy $PROJECT_ID --format=json | \
jq '.bindings[] | {scope: "project", role: .role, members: .members}'
# Find all org-level bindings for a specific user (highest blast radius)
USER_EMAIL="[email protected]"
gcloud organizations get-iam-policy $ORG_ID --format=json | \
jq --arg user "user:$USER_EMAIL" '.bindings[] | select(.members[] | contains($user)) | {role: .role, scope: "organization"}'

Exploitation

The scope of a role binding determines how dangerous it is:

  • Org-scoped bindings are the highest-risk: a single org-scoped roles/owner binding grants full control of the entire GCP organization.
  • Folder-scoped bindings affect all projects and SAs within the folder hierarchy — common in large orgs where teams share a folder.
  • Project-scoped bindings are the most constrained — least blast radius.

Attack path analysis traversal uses GCP_ROLE_SCOPED_TO to determine which resources an attack path edge targets:

  • Org-scoped roles/owner → GCP_SET_ORG_IAMPOLICY edge targets the org + GCP_SET_PROJECT_IAMPOLICY edges fan out to ALL projects.
  • Folder-scoped roles/owner → edges fan out to all projects within the folder hierarchy.
  • Project-scoped roles/owner → edges target only that specific project.

Mitigation

  1. Prefer project-scoped bindings — assign roles at the project level by default. Use folder scope only when the role genuinely needs to apply to all projects in the folder, and org scope only for infrastructure automation accounts.
  2. Audit all org-scoped bindings — these carry the highest blast radius; each should have a documented owner, purpose, and justification.
  3. Use Privileged Access Manager (PAM) for just-in-time activation of org- and folder-scoped privileged bindings instead of standing assignments.
  4. Remove over-broad legacy bindings that were scoped to org or folder but should be project-scoped.

Detection

Log Type Method Key Fields
Admin Activity SetIamPolicy at org scope Binding added to organization resource
Admin Activity SetIamPolicy at folder scope Binding added to folder resource
ORG_ID=$(gcloud organizations list --format="value(name)" | head -1)
gcloud logging read \
'protoPayload.methodName="SetIamPolicy" AND resource.type="organization"' \
--organization=$ORG_ID \
--format="table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.serviceData.policyDelta.bindingDeltas)"
gcloud logging read \
'protoPayload.methodName="SetIamPolicy" AND protoPayload.resourceName=~"folders/"' \
--organization=$ORG_ID \
--format="table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.resourceName)"

Alert on:

  • New privileged role bindings added at org or folder scope.
  • Any org-scoped SetIamPolicy call — org-level policy changes should be exceptionally rare and require change management approval.

References

Was this page helpful?

Thank you for your feedback.