← All field notes
gcpcloud buildsupply chainci cd

Your build pipeline shipped the attacker's code

GCP Cloud Build runs as a powerful service account and produces the artifacts you deploy. Tamper with the build and you have poisoned everything downstream, signed and trusted. Here is the supply-chain path, and the fix.

Attack flow
1Compromise a build trigger or source
2Inject into the Cloud Build config
3Build runs as the Cloud Build SA
4Ship a poisoned, trusted artifact
5Downstream compromise
Seen in the wildCI/CD and supply-chain attackersOpportunistic

The safest-looking artifact in your release pipeline is the one your own build system signed.

What it is

GCP Cloud Build executes your build steps as a Cloud Build service account that frequently holds broad project rights: push to Artifact Registry, deploy, read secrets. An attacker who can modify the build config (cloudbuild.yaml), the source, or a trigger injects malicious steps. The build runs as the trusted service account, bakes a backdoor into the artifact, and pushes it through your normal release path. This is T1195 (supply-chain compromise) with T1059 and T1552.

Why it works

The output is a legitimately built, signed, trusted artifact, so downstream systems accept it without question. The Cloud Build service account’s rights are usually broader than any single build needs.

How to detect it

In Cloud Audit Logs, watch for changes to triggers or build configs, builds from unexpected sources or branches, and the Cloud Build service account reaching secrets or registries it does not normally touch.

The fix that holds

Least-privilege the Cloud Build service account, protect the build config and triggers (review, branch protection, no untrusted pull-request builds), and pin plus verify dependencies. Use provenance and SLSA attestations so downstream verifies what built each artifact, and alert on trigger and config changes.

Practice it

We built a Cloud Build supply-chain scenario in GraphLattice Range so teams learn to defend the build itself, not just the running app.