Mitiga at RSAC 2025: Visit our booth, attend our speaking sessions, and schedule a meeting with us!

Key Points

  • This post introduces a novel privilege escalation technique in Google Cloud Platform (GCP) that exploits IAM Conditions in combination with tagBindings.
  • Attackers with seemingly low-risk roles like roles/resourcemanager.tagUser and roles/viewer can escalate privileges by attaching specific tags to resources, satisfying conditional IAM bindings and gaining elevated access.
  • In many organizations, tag permissions are not treated as sensitive or administrative, making this escalation path easy to overlook.
  • This behavior is not considered a vulnerability, as it results from misconfigured trust boundaries rather than a bug.
  • This technique shows how easy it is to take advantage of context-based IAM setups when tag usage isn’t properly locked down.

Introduction


GCP offers fine-grained access control using Identity and access management (IAM) Conditions, allowing organizations to restrict permissions based on context like request time, resource type and resource tags. But under the right conditions, those same tags can become a serious weak point. In this post, we present a novel method for escalating privileges in GCP, that takes advantage of tagBindings (the mechanism used to attach tags to resources). Surprisingly, a user with nothing more than the viewer and tagUser roles can end up with full admin access, without ever modifying IAM policies or assigning more roles to themselves. It’s easy to think that only tagAdmin is a sensitive role and that tagUser is safe to assign broadly, but is it really?

Background: IAM, Tags, and Everything in Between

IAM Conditions and Resource Tags


In GCP, access control is managed through IAM policies, which define who (members) has what role on which resource. Each policy can also include conditions that must be satisfied for access to be granted. These conditions can evaluate properties like request time, IP address, or resource tags.

Tags in GCP are key-value pairs associated with resources. They are typically used to organize resources, enforce access controls, and improve visibility across cloud environments. Tags can be inherited from folders or organizations, and IAM Conditions can reference them using functions like resource.matchTag('env', 'sandbox') or resource.hasTagKey('env').

Conditional Access Based on Tags


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"
    }
}

This IAM policy grants a specific role, in this case, roles/compute.admin, to members of the group sandbox_users@*************, but only if the target resource is tagged with env=sandbox. The role itself is not fixed, it could be any permission in the project (on a GCP service that supports tags), making this type of conditional access flexible but also potentially risky if misused.

TagBindings and Role-Based Tag Management


Furthermore, tags are attached to resources using tagBindings, which link a resource to a specific tagValue. in the platform, it looks like this:

Later in the blog, we’ll explain why linking a tag to a resource is a crucial part of this privilege escalation technique. we’ll also show how an attacker can become an admin on a resource just by attaching a tag like the one shown in the screenshot, to an existing resource they don’t have admin rights on.

Tag Management Roles


In terms of access control, tag management breaks down as follows:

  • roles/resourcemanager.tagViewer (Tag Viewer):
    Allows viewing existing tag keys, tag values, and the tag bindings applied to resources, including inherited tags.
  • roles/resourcemanager.tagUser (Tag User):
    Allows attaching and detaching existing tags to/from resources (via tag bindings), and inherits all tag viewing permissions. If the role is assigned at the organization level, this automatically ensures that the user has permission to attach it to every resource in the organization.
  • roles/resourcemanager.tagAdmin (Tag Administrator):
    Grants full management over tags, including creating, updating, deleting tag keys and values, and managing their IAM policies, in addition to all viewing capabilities.

This creates an interesting scenario: IAM policies can restrict access based on whether a tag is present, but GCP does not prevent a user with tag-binding permissions from adding that tag after the policy has already been applied.

The Attack Flow

TL;DR


Prerequisites to this scenario:

  1. A principal with the roles:
    1. roles/resourcemanager.tagUser
    2. roles/viewer
  2. An IAM policy which grants roles to “Members” (user, service account or group) based on tagBinding (tagBinding links tags to the Google Cloud resource) condition.
  3. TagKey/TagValue must already exist.
  4. The principal is included in the “members” (either as part of a group or explicitly listed).

The scenario:

An attacker with the above two roles wants to gain compute.admin privileges on any Compute Engine instance in the project. By combining visibility into IAM policies and existing tags with the ability to bind those tags, the attacker escalates their privileges.

  1. Enumerate IAM Policies
    The attacker queries the project’s IAM policy to find any conditional role bindings. This reveals a policy that grants compute.admin if the resource has the tag env=sandbox and the user is in a specific group.
  2. List Available Tags
    Using the viewer role, the attacker lists all tag keys and values configured in the environment. This allows them to identify the exact env=sandbox tag required to satisfy the IAM condition.
  3. Create the Tag Binding
    
The attacker has the roles/resourcemanager.tagUser role, so he binds the env=sandbox tag to a target Compute Engine instance. This action fulfills the IAM condition and grants them elevated access to that specific resource.
  4. Attempt write operation on cloud engine instance
    With the tag applied, the attacker reattempts the admin operation, and this time it succeeds. They now have full control over the instance, proving that the privilege escalation via tag binding was effective.

This diagram shows the privilege escalation flow in GCP when an attacker uses the tagUser role to bind a tag (e.g., env=sandbox) to a resource. By satisfying an IAM condition that grants elevated permissions based on that tag, the attacker gains full admin access to the resource without modifying the IAM policy directly.

Step-by-Step Breakdown: How the Attacker Pulls It Off


The attacker starts by signing in and assessing their current access. They begin by reviewing which roles they have across the environment:


At first glance, it looks like the user has only two roles:

  • roles/resourcemanager.tagUser
  • roles/viewer

This is how it appears in the Cloud Console:


But could this user have more privileges than it seems? Let’s check the IAM policy of the project.


As we can see, there’s an IAM binding condition that grants the roles/compute.admin role only if the resource is tagged with env=sandbox, and only to principals in the group sandbox_users@*************.

This raises a question: what happens if the attacker adds that tag to a resource that isn't actually part of the sandbox?

Since the user has the roles/viewer role, they can enumerate all existing tag keys and values in the environment. So let’s list them.


This is how it appears in the Cloud Console:

Next, let’s add this tag to a Compute Engine instance the attacker wants access to. This works because the user also has the roles/tagUser role.


Now let’s attempt an operation that requires more privileges than what roles/viewer provides.


The operation succeeds!
The attacker has just removed the public IP from the instance.

In fact, the attacker can tag any Compute Engine instance in the environment and gain full admin access, including the ability to delete it, modify its configuration, or assign a new public IP.

But what does it really mean to have compute.admin on every VM in the environment? Does it mean the attacker can now impersonate the VM's service accounts and pivot further across the project?

Not exactly.

GCP explicitly separates VM management from service account impersonation. Even though roles/compute.admin lets you manage the VM, including which service account it uses, it does not allow you to impersonate that service account or fetch its token.

Why?

Because GCP treats VM control and identity access as distinct permission boundaries. Without serviceAccountTokenCreator, the attacker cannot call generateAccessToken or use the gcloud auth print-access-token path.

However, there is a workaround.

If the attacker can SSH into the VM (which they can as compute.admin), they can query the VM's metadata server to extract a live token issued to the service account:


With this token in hand, the attacker can make API calls as the VM's service account, fully bypassing the lack of TokenCreator permissions. So while GCP's permission model is secure by design, misconfigured VMs with overly permissive service accounts still create real opportunities for lateral movement and privilege escalation.

Impact


This privilege escalation vector bypasses intended access restrictions and can result in:

  • Unauthorized access to sensitive resources.
  • Full administrative control of systems like Cloud SQL, Compute Engine, or others that support tagBindings.
  • Persistence via IAM roles that appear legitimate.

Since tags are evaluated dynamically, any future tag-based conditions can also be manipulated by an attacker with tagBinding access.

Moreover, dozens of publicly available Terraform modules assign tagUser to application teams or CI/CD service accounts, evidence that the role is often given to nonadministrators, making the misconfiguration realistic. for example:

Detection


So how can this attack be detected in the logs?

The individual steps of the attack, like listing tags or reading IAM policies, are pretty common and not suspicious on their own. But when you look at them together, especially when followed by a tag binding and a privileged action, they start to tell a different story.

To do that, we wrote a Sigma detection logic that looks for this exact sequence:

  1. IAM policy listing
  2. Tag key/value listing
  3. Creation of a tag binding
  4. A privileged operation shortly after (on the same resource, by the same principal)
title: GCP Privilege Escalation via TagBinding
id: GCP-PRIVESC-TAGBINDING
description: >
  Detects a sequence in GCP logs where a user enumerates IAM policies and tags,
  binds a tag to a resource, and then performs a privileged action on that resource.
logsource:
  category: cloud.audit
  product: gcp
detection:
  selection_enum_iam_tags:
    methodName|contains:
      - "GetIamPolicy"
      - "TagKeys.ListTagKeys"
      - "TagKeys.ListTagValues"
      - "TagBindings.ListEffectiveTags"

  selection_tag_binding:
    methodName: "TagBindings.CreateTagBinding"

  selection_privileged:
    methodName|in: # Assume this is a list of privileged API methods
      - "beta.compute.images.setIamPolicy"
      - "beta.storage.buckets.setIamPolicy"
      # ...add more privileged operations

  timeframe: 15m

  condition: selection_enum_iam_tags followed by 
             selection_tag_binding followed by 
             selection_privileged
fields:
  - principalEmail
  - resourceName
  - methodName
  - timestamp
  - project_id
level: high
tags:
  - attack.privilege_escalation
  - attack.t1548
  - gcp
  - iam
  - tagbinding

Recommendations


To mitigate this issue:

  • Treat tag management as privileged.
    Only grant roles/resourcemanager.tagUser or higher to trusted automation or admin identities. Avoid assigning this role to general-purpose developer, viewer, or CI/CD accounts.
  • Separate tagging and access boundaries.
    Avoid designing IAM Conditions where the same identity can both set a tag and benefit from that tag. Access to tagBindings should belong to a separate admin or automation identity.
  • Use deny policies or org policies to block risky combinations.
    GCP Organization Policy Constraints like constraints/iam.allowedPolicyMemberDomains and custom Deny Policies can be used to limit who can bind tags on sensitive resources.
  • Restrict tag inheritance scope.
    Use folder and project structure to limit how tags are inherited and which identities can modify tags at different hierarchy levels.

Conclusion


Tags in GCP are a powerful way to organize and manage resources, but when they're used in IAM Conditions, they become part of the security model. That’s where the risk begins. In many organizations, roles like tagUser are handed out to support automation or reporting tasks, not realizing that they can directly influence access decisions.

This technique highlights how privilege escalation can occur not just through a bug, but also through misaligned assumptions between how tags are used and how access is enforced. What looks like harmless metadata suddenly becomes the key to admin access.

Security teams should treat tag management as a privileged operation, especially when tag-based IAM bindings are involved. Least privilege must extend to tagging workflows, and conditional access should always assume that context (like tags) can be manipulated unless explicitly protected.

About the author

Ariel Kalman

Ariel Kalman is a Senior Security Researcher at Mitiga, actively engaged in cloud-related security research. With a specialization in application security, Ariel excels in discovering new attack vectors associated to cloud environments.

Ariel's LinkedIn: https://www.linkedin.com/in/ariel-kalman-47314a19b/

LAST UPDATED:

April 24, 2025

Don't miss these stories:

Who Touched My GCP Project? Understanding the Principal Part in Cloud Audit Logs – Part 2

This second part of the blog series continues the path to understanding principals and identities in Google Cloud Platform (GCP) Audit Logs. Part one introduced core concepts around GCP logging, the different identity types, service accounts, authentication methods, and impersonation.

Make Cloud Attacks Yesterday’s Problem with Mitiga at RSA Conference 2025

Visit Mitiga at booth number N-4618 at RSA Conference 2025 to learn about cloud detection and response.

Mitiga Cooperates with Law Enforcement on a Global BEC

Mitiga has worked with a law enforcement investigation to prevent criminals from impersonating Office 365 executives and redirecting wire transfers. Learn more.

How Missing Logs Impact Cloud Security

Microsoft experienced an issue with internal monitoring agents, resulting in incomplete logs for some services. Get more details and recommended next steps.

Unlocking Cloud Security with Managed Detection and Response

See how Mitiga’s Cloud Managed Detection and Response tackles complex cyber threats with proactive threat management and advanced automation at scale.

Mitiga Cloud Managed Detection and Response (C-MDR) Reduces Alert Fatigue and Bolsters SecOps Resources

Learn about Mitiga’s fully-managed cloud detection and response service that operates 24/7.