gcp-cloudbuild-pubsub-trigger

A principal with pubsub.topics.publish on a trigger's configured Pub/Sub topic can fire that trigger, potentially executing code as the trigger's SA.

derived gcp emits CanTrigger

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

?principal CanTrigger ?topic ?topic CanTrigger ?trigger

where

node_type(?topic) == Topic node_type(?trigger) == BuildWorker ?principal has effective pubsub.topics.publish on ?topic ?trigger.pubsubConfig.topic == ?topic.native_id

emit

source typeIdentity
target typeCompute
source<principal with pubsub.topics.publish on ?topic>
target<Cloud Build trigger node (BuildWorker)>
permissionspubsub.topics.publish
conditionsattacker_influenced_definition
state logicCONDITIONAL(attacker_influenced_definition): Pub/Sub publish fires the trigger, which runs the CURRENT build definition. Escalation to CanExecuteAs requires the definition to be attacker-influenced (same condition as gcp-cloudbuild-trigger-run). If the trigger's build spec is attacker-controlled (inlineBuild under attacker control, or already poisoned via trigger update): ACTIVE for CanExecuteAs once cicd-chains processes this CanTrigger + ExecutesAs. If the topic is public (allUsers publish): ExposedToInternet feeds here.

Narrative

{principal.name} can publish to Pub/Sub topic {topic.name} (pubsub.topics.publish), which fires Cloud Build trigger {trigger.name}; if the trigger's build definition is attacker-influenced, this executes code as the trigger's SA {sa.name}.

Raw rule rules/derived/gcp/cloudbuild.yaml

id: gcp-cloudbuild-pubsub-trigger
emits: CanTrigger
description: A principal with pubsub.topics.publish on a trigger's configured Pub/Sub topic can fire that
  trigger, potentially executing code as the trigger's SA.
match:
- - ?principal
  - CanTrigger
  - ?topic
- - ?topic
  - CanTrigger
  - ?trigger
where:
- node_type(?topic) == Topic
- node_type(?trigger) == BuildWorker
- ?principal has effective pubsub.topics.publish on ?topic
- ?trigger.pubsubConfig.topic == ?topic.native_id
emit:
  source_type: Identity
  target_type: Compute
  source: <principal with pubsub.topics.publish on ?topic>
  target: <Cloud Build trigger node (BuildWorker)>
  permissions:
  - pubsub.topics.publish
  conditions:
  - attacker_influenced_definition
  state_logic: 'CONDITIONAL(attacker_influenced_definition): Pub/Sub publish fires the trigger, which
    runs the CURRENT build definition. Escalation to CanExecuteAs requires the definition to be attacker-influenced
    (same condition as gcp-cloudbuild-trigger-run). If the trigger''s build spec is attacker-controlled
    (inlineBuild under attacker control, or already poisoned via trigger update): ACTIVE for CanExecuteAs
    once cicd-chains processes this CanTrigger + ExecutesAs. If the topic is public (allUsers publish):
    ExposedToInternet feeds here.'
  confidence: 0.7
  derived_from:
  - <pubsubConfig.topic field from BuildTrigger>
  - <pubsub.topics.publish effective permission>
  false_positive_note: "Pub/Sub publish alone is not code execution \u2014 it fires the trigger, which\
    \ runs the existing definition. Downgrade to CONDITIONAL unless the build definition is demonstrably\
    \ attacker-influenced. Also check whether the trigger has a subscription filter (messageBody filter\
    \ conditions) that limit which messages fire the build \u2014 an overly restrictive filter may prevent\
    \ arbitrary triggering."
  narrative: '{principal.name} can publish to Pub/Sub topic {topic.name} (pubsub.topics.publish), which
    fires Cloud Build trigger {trigger.name}; if the trigger''s build definition is attacker-influenced,
    this executes code as the trigger''s SA {sa.name}.'
move · open · esc close