gcp-run-execute-as-via-update

Modify code/config of an existing Cloud Run resource; it runs as its existing runtime SA.

derived gcp emits CanExecuteAs

match

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

?principal CanModifyCode ?resource ?resource ExecutesAs ?sa

where

node_type(?resource) in [ContainerService, ServerlessFunction] ?sa.privilege_level >= ?principal.privilege_level

optional

Present → upgrade the emitted state; absent → downgrade (not a hard requirement).

?principal CanInvoke ?resource

emit

source typeIdentity
target typeIdentity
source<principal>
target<runtime service account>
permissionsrun.services.update run.jobs.update run.workerpools.update run.routes.invoke run.jobs.run
state logicif node_type(?resource)==ContainerService AND provider_type(?resource)==google.cloud.run.WorkerPool: ACTIVE (worker pools are pull-based and run continuously once a revision deploys — no invoke/trigger needed); elif matched(optional[0]) or trigger_exists(?resource): ACTIVE else CONDITIONAL(trigger_exists)

Narrative

{principal.name} can execute as {sa.name} by deploying a malicious revision of {resource.name} (run.services.update) and invoking it (run.routes.invoke).

Raw rule rules/derived/gcp/cloudrun.yaml

id: gcp-run-execute-as-via-update
emits: CanExecuteAs
description: Modify code/config of an existing Cloud Run resource; it runs as its existing runtime SA.
match:
- - ?principal
  - CanModifyCode
  - ?resource
- - ?resource
  - ExecutesAs
  - ?sa
where:
- node_type(?resource) in [ContainerService, ServerlessFunction]
- ?sa.privilege_level >= ?principal.privilege_level
optional:
- - ?principal
  - CanInvoke
  - ?resource
emit:
  source_type: Identity
  target_type: Identity
  source: <principal>
  target: <runtime service account>
  state_logic: "if node_type(?resource)==ContainerService AND provider_type(?resource)==google.cloud.run.WorkerPool:\
    \ ACTIVE (worker pools are pull-based and run continuously once a revision deploys \u2014 no invoke/trigger\
    \ needed); elif matched(optional[0]) or trigger_exists(?resource): ACTIVE else CONDITIONAL(trigger_exists)"
  permissions:
  - run.services.update
  - run.jobs.update
  - run.workerpools.update
  - run.routes.invoke
  - run.jobs.run
  conditions_from:
  - ?resource
  - ?sa
  escalation: Swap the image of a Cloud Run resource, then invoke/trigger it to run code as its runtime
    SA. For worker pools, deploying a malicious revision to the existing pool executes immediately (continuous
    pull-based execution).
  derived_from:
  - <CanModifyCode edge_id>
  - <ExecutesAs edge_id>
  - <optional CanInvoke edge_id>
  false_positive_note: "Target the resource's EXISTING runtime SA (often the default compute SA with roles/editor),\
    \ not an arbitrary SA. If no invoker binding and no trigger exists, state is CONDITIONAL(trigger_exists)\
    \ \u2014 for a public service (allUsers invoker) it is ACTIVE."
  narrative: '{principal.name} can execute as {sa.name} by deploying a malicious revision of {resource.name}
    (run.services.update) and invoking it (run.routes.invoke).'
move · open · esc close