gcp-sr-push-is-code-modify
A principal with source.repos.update can push commits to the CSR repository, including a modified cloudbuild.yaml - the code-supply-chain write primitive that arms any Cloud Build push trigger watching the target branch.
match (effective permission)
{
"action": "source.repos.update",
"resource_type": "google.sourcerepo.Repository"
}
emit
| source type | Identity |
|---|---|
| target type | ArtifactRepository |
| source | <principal> |
| target | <CSR Repository in scope> |
| permissions | source.repos.update |
| state logic | ACTIVE when source.repos.update is effective (not denied by IAM deny policy) and the push target branch is unwatched or branch protection is not enforced. CONDITIONAL(branch_protection) when the Cloud Build trigger watches only a protected branch (e.g. main) that requires code review or an admin merge before the push lands; in this case the attacker can push to the repo but not to the branch the trigger fires on without additional privilege. BLOCKED if an IAM deny policy denies source.repos.update or a VPC-SC perimeter that includes sourcerepo.googleapis.com rejects the API call from outside the perimeter. Inherit weakest from contributing role binding. Project-level source.repos.update applies to ALL repos in the project; emit one CanModifyCode per in-scope repository. |
Narrative
{principal.name} holds source.repos.update on repository {repo.name} and can push commits to it, including a modified cloudbuild.yaml or build-spec changes. Any Cloud Build push trigger watching the target branch will fire and run the attacker-modified build definition as the Cloud Build service account, yielding code execution with that SA's permissions. cicd-chains::cicd-modify-buildspec-executes-as collapses this into CanExecuteAs(principal -> CloudBuildSA) when the trigger+ExecutesAs chain is present.
Raw rule rules/derived/gcp/sourcerepos.yaml
id: gcp-sr-push-is-code-modify
emits: CanModifyCode
description: "A principal with source.repos.update can push commits to the CSR repository, including a\
\ modified cloudbuild.yaml \u2014 the code-supply-chain write primitive that arms any Cloud Build push\
\ trigger watching the target branch."
match_effective_permission:
action: source.repos.update
resource_type: google.sourcerepo.Repository
emit:
source_type: Identity
target_type: ArtifactRepository
source: <principal>
target: <CSR Repository in scope>
permissions:
- source.repos.update
conditions: []
state_logic: ACTIVE when source.repos.update is effective (not denied by IAM deny policy) and the push
target branch is unwatched or branch protection is not enforced. CONDITIONAL(branch_protection) when
the Cloud Build trigger watches only a protected branch (e.g. main) that requires code review or an
admin merge before the push lands; in this case the attacker can push to the repo but not to the branch
the trigger fires on without additional privilege. BLOCKED if an IAM deny policy denies source.repos.update
or a VPC-SC perimeter that includes sourcerepo.googleapis.com rejects the API call from outside the
perimeter. Inherit weakest from contributing role binding. Project-level source.repos.update applies
to ALL repos in the project; emit one CanModifyCode per in-scope repository.
confidence: 0.95
derived_from:
- 'effective permission: source.repos.update on <repo>'
false_positive_note: "Branch protection is the primary false-positive risk. CSR's native branch- protection\
\ support is limited compared to GitHub; verify whether the Cloud Build trigger filters to a specific\
\ branch ref and whether CSR enforces any push restrictions (via IAM conditions or org policy) on\
\ that branch. A push to a branch the trigger does NOT watch does not arm the trigger; scope CanModifyCode\
\ to a branch the attacker can write AND the trigger watches. VPC-SC enforcement (non-dry-run) on\
\ sourcerepo.googleapis.com blocks all API calls from principals outside the perimeter; emit BLOCKED\
\ for those. Do NOT emit CanExecuteAs here \u2014 cicd-chains owns that derivation via the Cloud Build\
\ trigger's ContainsResourceReference(trigger -> repo) link."
narrative: '{principal.name} holds source.repos.update on repository {repo.name} and can push commits
to it, including a modified cloudbuild.yaml or build-spec changes. Any Cloud Build push trigger watching
the target branch will fire and run the attacker-modified build definition as the Cloud Build service
account, yielding code execution with that SA''s permissions. cicd-chains::cicd-modify-buildspec-executes-as
collapses this into CanExecuteAs(principal -> CloudBuildSA) when the trigger+ExecutesAs chain is present.'