gcp-cloudbuild-trigger-run

cloudbuild.triggers.run lets the principal fire an existing trigger at a chosen source revision; code execution as the trigger's SA is CONDITIONAL on the current definition being attacker-influenced.

derived gcp emits CanTrigger

match (effective permission)

{ "action": "cloudbuild.triggers.run", "resource_type": "google.devtools.cloudbuild.v1.BuildTrigger" }

emit

source typeIdentity
target typeCompute
source<principal>
target<Cloud Build trigger node / BuildWorker>
permissionscloudbuild.triggers.run
conditionsattacker_influenced_definition
state logicCONDITIONAL(attacker_influenced_definition): triggers.run executes the CURRENT trigger definition. This becomes ACTIVE code execution as the trigger's SA only if: (a) the trigger builds from a branch/commit the attacker controls (so the source revision arg lets the attacker choose an attacker-authored commit), OR (b) the trigger's build spec references unpinned/mutable config the attacker can poison (dependency, GCS bucket), OR (c) the trigger's inline build spec was already tampered (by gcp-cloudbuild-trigger-update-code). A trigger.run over a fully pinned, reviewed definition with no attacker-reachable inputs stays CONDITIONAL, not ACTIVE. Inherits BLOCKED if a deny policy applies to triggers.run.

Narrative

{principal.name} can fire Cloud Build trigger {trigger.name} (cloudbuild.triggers.run) at a chosen source revision; if the trigger's build definition is attacker-influenced (attacker-controlled branch, unpinned dependency, or already-poisoned spec), this executes code as the trigger's SA.

Raw rule rules/derived/gcp/cloudbuild.yaml

id: gcp-cloudbuild-trigger-run
emits: CanTrigger
description: cloudbuild.triggers.run lets the principal fire an existing trigger at a chosen source revision;
  code execution as the trigger's SA is CONDITIONAL on the current definition being attacker-influenced.
match_effective_permission:
  action: cloudbuild.triggers.run
  resource_type: google.devtools.cloudbuild.v1.BuildTrigger
emit:
  source_type: Identity
  target_type: Compute
  source: <principal>
  target: <Cloud Build trigger node / BuildWorker>
  permissions:
  - cloudbuild.triggers.run
  conditions:
  - attacker_influenced_definition
  state_logic: 'CONDITIONAL(attacker_influenced_definition): triggers.run executes the CURRENT trigger
    definition. This becomes ACTIVE code execution as the trigger''s SA only if: (a) the trigger builds
    from a branch/commit the attacker controls (so the source revision arg lets the attacker choose an
    attacker-authored commit), OR (b) the trigger''s build spec references unpinned/mutable config the
    attacker can poison (dependency, GCS bucket), OR (c) the trigger''s inline build spec was already
    tampered (by gcp-cloudbuild-trigger-update-code). A trigger.run over a fully pinned, reviewed definition
    with no attacker-reachable inputs stays CONDITIONAL, not ACTIVE. Inherits BLOCKED if a deny policy
    applies to triggers.run.'
  confidence: '0.70'
  derived_from:
  - <cloudbuild.triggers.run effective permission>
  false_positive_note: "Do NOT emit ACTIVE merely because the principal can run the trigger \u2014 the\
    \ CURRENT definition must be demonstrably attacker-influenced for CanExecuteAs to be ACTIVE. The classic\
    \ ACTIVE case is a trigger that builds from a public fork / untrusted PR (pwn-request pattern) or\
    \ an unpinned Dockerfile FROM / base image the attacker can push to. cicd-chains cicd-trigger-runner-executes-as\
    \ handles the CONDITIONAL -> CanExecuteAs collapse; do not re-derive here."
  narrative: '{principal.name} can fire Cloud Build trigger {trigger.name} (cloudbuild.triggers.run) at
    a chosen source revision; if the trigger''s build definition is attacker-influenced (attacker-controlled
    branch, unpinned dependency, or already-poisoned spec), this executes code as the trigger''s SA.'
move · open · esc close