Cloud Security Wire
AWS Azure GCP RSS
GCP Hardening Guide

GCP Vertex AI Agent Engine: Default Service Accounts Are Over-Privileged and That's a Real Attack Path

Google's Vertex AI Agent Engine creates a default service agent with permissions that extend well beyond what most deployments need -- including access to Cloud Storage, BigQuery, Pub/Sub, and potentially Google Workspace. Unit 42's 'Double Agents' research confirmed the attack path from viewer-level access to project-wide credential theft. Here's how to harden it.

By Cloud Security Wire · ·
#GCP#Vertex AI#Agent Engine#service account#privilege escalation#IAM#BYOSA#lateral movement#cloud security#Google Cloud#AI security

Google’s Vertex AI Agent Engine makes it easy to deploy and manage AI agents at scale. What it does not do by default is apply the principle of least privilege to the service account those agents run under.

Unit 42 published research in April 2026 — the “Double Agents” paper — documenting exactly how far the default service agent permissions extend. A user with Viewer-level access to a GCP project can extract service agent credentials from the instance metadata service and obtain project-wide access to Cloud Storage, BigQuery, Pub/Sub, and Artifact Registry. In some configurations, those scopes extend into the organisation’s Google Workspace: Gmail, Calendar, Drive.

Google classified both reported vulnerabilities as working as intended and recommended that customers use Bring Your Own Service Account (BYOSA) to replace the default service agent. This guide covers what the attack path looks like, why the defaults are dangerous, and how to remediate.

What the Default Service Agent Looks Like

When you create an Agent Engine resource, GCP automatically creates or reuses a service agent with the format:

[email protected]

This service agent is granted the roles/aiplatform.serviceAgent role. The problem is what that role includes. The Vertex AI service agent role has broad permissions across GCP services — it is designed to support the full range of things Vertex AI might need to do, including:

  • Reading from and writing to Cloud Storage
  • Querying BigQuery datasets
  • Publishing to Pub/Sub topics
  • Pulling from Artifact Registry

In the Agent Engine context, most deployments do not need all of these. A simple conversational agent that queries an external API does not need BigQuery access. But it gets it.

The Attack Path

The Unit 42 researchers documented this as a privilege escalation scenario accessible from a low-privileged starting point.

Step 1: Low-privileged access. An attacker with Viewer-level project access (or any principal that can interact with Agent Engine resources) can request the service agent’s access token from the GCP metadata server accessible from within Agent Engine’s execution environment.

Step 2: Token retrieval. From inside an Agent Engine session, the metadata service is reachable at http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token. This returns a short-lived OAuth2 token for the service agent.

Step 3: Lateral movement. The token is usable against any GCP API the service agent has permission to call. The attacker now has project-wide Cloud Storage access, can query BigQuery datasets, and can access any resource within the service agent’s IAM scope.

Step 4: Google Workspace access. In organisations where the default service agent has been granted Google Workspace delegation (which can happen automatically depending on how the project was configured), the token can be used to access Gmail, Google Calendar, and Google Drive for any user in the Workspace tenant.

This is not a bug in the metadata service — that service is functioning as designed. The problem is the combination of over-broad default permissions and the accessibility of the metadata endpoint from within the execution environment.

Remediation: BYOSA (Bring Your Own Service Account)

The recommended fix is to create a dedicated service account with only the permissions your agent actually needs, and configure Agent Engine to use that account instead of the default service agent.

Step 1: Create a minimal service account

# Create a new service account for your agent
gcloud iam service-accounts create vertex-agent-sa \
  --description="Minimal SA for Vertex AI Agent Engine" \
  --display-name="Vertex AI Agent Engine SA"

Step 2: Grant only the permissions your agent needs

PROJECT_ID="your-project-id"
SA_EMAIL="vertex-agent-sa@${PROJECT_ID}.iam.gserviceaccount.com"

# Example: Agent only needs to read from one specific GCS bucket
gcloud storage buckets add-iam-policy-binding gs://your-agent-data-bucket \
  --member="serviceAccount:${SA_EMAIL}" \
  --role="roles/storage.objectViewer"

# Do NOT grant roles/storage.admin, roles/bigquery.dataViewer at project level,
# or any other permission the agent doesn't directly require

Step 3: Configure Agent Engine to use the custom SA

When creating or updating your Agent Engine resource, specify the service account:

from google.cloud import aiplatform

# Create agent with custom service account
agent = aiplatform.Agent.create(
    display_name="my-agent",
    service_account=f"vertex-agent-sa@{project_id}.iam.gserviceaccount.com",
    # ... other configuration
)

Or via Terraform:

resource "google_vertex_ai_agent_engine" "agent" {
  display_name    = "my-agent"
  project         = var.project_id
  location        = "us-central1"
  service_account = google_service_account.agent_sa.email
  
  # ... other configuration
}

resource "google_service_account" "agent_sa" {
  account_id   = "vertex-agent-sa"
  display_name = "Vertex AI Agent Engine SA"
  project      = var.project_id
}

Step 4: Prevent metadata service abuse

Even with a minimal custom service account, restrict what can call the metadata service from within your agent’s execution context. In Agent Engine, you can constrain outbound network calls using VPC Service Controls:

# Create a service perimeter that restricts metadata access patterns
# (requires VPC Service Controls to be configured for your org)
gcloud access-context-manager perimeters create vertex-agent-perimeter \
  --policy=POLICY_ID \
  --title="Vertex AI Agent Perimeter" \
  --resources=projects/PROJECT_NUMBER \
  --restricted-services="aiplatform.googleapis.com"

Auditing Existing Deployments

To identify over-privileged service agents in your current GCP projects:

# List all service accounts with aiplatform service agent roles
gcloud projects get-iam-policy PROJECT_ID \
  --flatten="bindings[].members" \
  --format="table(bindings.role,bindings.members)" \
  --filter="bindings.members:gcp-sa-aiplatform.iam.gserviceaccount.com"

To check the effective permissions of the default service agent:

# Get the service agent email
SERVICE_AGENT=$(gcloud iam service-accounts list \
  --filter="email:gcp-sa-aiplatform.iam.gserviceaccount.com" \
  --format="value(email)" \
  --project=PROJECT_ID)

# List all IAM bindings for this service account
gcloud projects get-iam-policy PROJECT_ID \
  --flatten="bindings[].members" \
  --format="table(bindings.role)" \
  --filter="bindings.members:${SERVICE_AGENT}"

Monitoring for Metadata Service Abuse

Cloud Logging captures authentication events including service account token generation. Alert on unusual patterns:

# Cloud Logging query: service account token requests from unexpected principals
resource.type="service_account"
protoPayload.methodName="google.iam.credentials.v1.IAMCredentials.GenerateAccessToken"
protoPayload.authenticationInfo.principalEmail=~"gcp-sa-aiplatform"
protoPayload.requestMetadata.callerIp!="35.190.0.0/16"

Adjust the IP range filter to your Agent Engine execution environment’s known IP ranges.

The Broader Pattern

The Vertex AI Agent Engine case is an instance of a broader pattern in AI cloud services: the platforms are built for capability and developer experience, and security hardening is left to the operator. Default service agents in Vertex AI, default IAM roles in AWS Bedrock, and default execution contexts in Azure AI services are all configured for maximum compatibility.

For new Vertex AI deployments, BYOSA should be the default posture. The effort to create a minimal service account is low; the blast radius reduction in the event of a compromised agent session is significant.

For existing deployments, audit service agent permissions and narrow them to what the agent actually calls. The permissions granted to roles/aiplatform.serviceAgent exceed what most agents require, and there is no operational cost to restricting them through a custom SA.

References

← All Analysis Subscribe via RSS