gcp-run-execute-as-via-update
Modify code/config of an existing Cloud Run resource; it runs as its existing runtime SA.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
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 type | Identity |
|---|---|
| target type | Identity |
| source | <principal> |
| target | <runtime service account> |
| permissions | run.services.update run.jobs.update run.workerpools.update run.routes.invoke run.jobs.run |
| 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 — 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).'