gcp-deploy-release-create-modifies-code
clouddeploy.releases.create with actAs on the render SA injects attacker-controlled Skaffold config/hooks into the render Cloud Build worker.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
?principal has effective clouddeploy.releases.create on the delivery pipeline
?render_sa is the render-phase execution SA for the pipeline's first target
?render_sa is bound via
CanPassIdentity through iam.serviceAccounts.actAs (gcp-sa-act-as)
emit
| source type | Identity |
|---|---|
| target type | BuildWorker |
| source | ?principal |
| target | <render-phase Cloud Build worker (BuildWorker) for the delivery pipeline> |
| permissions | clouddeploy.releases.create iam.serviceAccounts.actAs |
| conditions | iam_permission |
| state logic | ACTIVE when ?principal holds effective clouddeploy.releases.create AND CanPassIdentity(?principal -> ?render_sa) is ACTIVE (iam.serviceAccounts.actAs confirmed on ?render_sa). CONDITIONAL(iam_permission) when actAs is unconfirmed (runtime SA lookup inconclusive). BLOCKED when an IAM deny policy or org policy denies either permission. |
Narrative
{principal.name} can create a Cloud Deploy release (clouddeploy.releases.create) with attacker-controlled Skaffold configuration, injecting arbitrary code into the render Cloud Build worker that runs as {render_sa.name}. actAs on {render_sa.name} is required (iam.serviceAccounts.actAs). Cite cicd-chains cicd-modify-buildspec-executes-as to collapse CanModifyCode + ExecutesAs into CanExecuteAs({principal} → {render_sa}).
Raw rule rules/derived/gcp/clouddeploy.yaml
id: gcp-deploy-release-create-modifies-code
emits: CanModifyCode
description: clouddeploy.releases.create with actAs on the render SA injects attacker-controlled Skaffold
config/hooks into the render Cloud Build worker.
applies_to:
- gcp
match:
- - principal: null
- CanPassIdentity
- render_sa: null
where:
- ?principal has effective clouddeploy.releases.create on the delivery pipeline
- ?render_sa is the render-phase execution SA for the pipeline's first target
- ?render_sa is bound via CanPassIdentity through iam.serviceAccounts.actAs (gcp-sa-act-as)
emit:
source_type: Identity
target_type: BuildWorker
source: ?principal
target: <render-phase Cloud Build worker (BuildWorker) for the delivery pipeline>
permissions:
- clouddeploy.releases.create
- iam.serviceAccounts.actAs
conditions:
- iam_permission
state_logic: ACTIVE when ?principal holds effective clouddeploy.releases.create AND CanPassIdentity(?principal
-> ?render_sa) is ACTIVE (iam.serviceAccounts.actAs confirmed on ?render_sa). CONDITIONAL(iam_permission)
when actAs is unconfirmed (runtime SA lookup inconclusive). BLOCKED when an IAM deny policy or org
policy denies either permission.
confidence: 0.95
derived_from:
- ?principal CanPassIdentity ?render_sa (gcp-sa-act-as)
- clouddeploy.releases.create effective permission
false_positive_note: "actAs on the render SA is the mandatory gate \u2014 without it the releases.create\
\ API call is rejected. Do NOT emit without confirmed CanPassIdentity. The render SA and deploy SA\
\ may differ; this edge applies only to the RENDER phase worker. Skaffold hooks (before/after deploy\
\ hooks, custom actions) execute inside the Cloud Build worker; control of skaffold.yaml is full code\
\ execution as the SA."
narrative: "{principal.name} can create a Cloud Deploy release (clouddeploy.releases.create) with attacker-controlled\
\ Skaffold configuration, injecting arbitrary code into the render Cloud Build worker that runs as\
\ {render_sa.name}. actAs on {render_sa.name} is required (iam.serviceAccounts.actAs). Cite cicd-chains\
\ cicd-modify-buildspec-executes-as to collapse CanModifyCode + ExecutesAs into CanExecuteAs({principal}\
\ \u2192 {render_sa})."