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.

derived gcp emits CanModifyCode

match (effective permission)

{ "action": "source.repos.update", "resource_type": "google.sourcerepo.Repository" }

emit

source typeIdentity
target typeArtifactRepository
source<principal>
target<CSR Repository in scope>
permissionssource.repos.update
state logicACTIVE 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.'
move · open · esc close