gcp-composer-update-env-inject-packages
composer.environments.update with softwareConfig.pypiPackages injects an attacker-controlled Python package installed on all workers and the scheduler, executing code as the environment SA at import time.
match (effective permission)
{
"action": "composer.environments.update",
"resource_type": "google.composer.Environment"
}
where
update targets config.softwareConfig.pypiPackages OR config.softwareConfig.envVariables OR config.softwareConfig.airflowConfigOverrides
no SA swap in this update path (separate rule gcp-composer-update-env-attach-sa covers SA swap)
emit
| source type | Identity |
|---|---|
| target type | AnalyticsService |
| source | <principal> |
| target | <Composer Environment node> |
| permissions | composer.environments.update |
| state logic | ACTIVE when composer.environments.update is confirmed in the effective grant at project or environment scope. The package installation requires an environment update cycle (minutes) and a worker restart — emit as ACTIVE for the code-injection capability with a note that execution is delayed by the update propagation time. The downstream CanExecuteAs (from can-execute-as execute-as-via-code-modify: CanModifyConfiguration is treated as equivalent to CanModifyCode when it achieves code injection) is ACTIVE once the update propagates. BLOCKED if an IAM deny policy applies to composer.environments.update. |
Narrative
{principal.name} can update Composer environment {env.name} (composer.environments.update) to add an attacker-controlled Python package to softwareConfig.pypiPackages; the package is installed on all worker pods and the scheduler and executes at Python import time as the environment SA {sa.name}. No actAs permission is required for this path (unlike SA-swap updates).
Raw rule rules/derived/gcp/composer.yaml
id: gcp-composer-update-env-inject-packages
emits: CanModifyConfiguration
description: composer.environments.update with softwareConfig.pypiPackages injects an attacker-controlled
Python package installed on all workers and the scheduler, executing code as the environment SA at import
time.
match_effective_permission:
action: composer.environments.update
resource_type: google.composer.Environment
where:
- update targets config.softwareConfig.pypiPackages OR config.softwareConfig.envVariables OR config.softwareConfig.airflowConfigOverrides
- no SA swap in this update path (separate rule gcp-composer-update-env-attach-sa covers SA swap)
emit:
source_type: Identity
target_type: AnalyticsService
source: <principal>
target: <Composer Environment node>
permissions:
- composer.environments.update
conditions: []
state_logic: "ACTIVE when composer.environments.update is confirmed in the effective grant at project\
\ or environment scope. The package installation requires an environment update cycle (minutes) and\
\ a worker restart \u2014 emit as ACTIVE for the code-injection capability with a note that execution\
\ is delayed by the update propagation time. The downstream CanExecuteAs (from can-execute-as execute-as-via-code-modify:\
\ CanModifyConfiguration is treated as equivalent to CanModifyCode when it achieves code injection)\
\ is ACTIVE once the update propagates. BLOCKED if an IAM deny policy applies to composer.environments.update."
confidence: 0.9
derived_from:
- <composer.environments.update effective permission>
false_positive_note: "This requires specifying an attacker-controlled PyPI package (e.g., a typosquat\
\ or a private package the attacker controls). Injecting a package that performs a no-op is not code\
\ execution \u2014 the package must contain malicious import-time code. The update takes minutes and\
\ workers are restarted; not an instant execution like the dags/ write path. CanModifyConfiguration\
\ is ACTIVE for the configuration capability, but the code-execution consequence (downstream CanExecuteAs)\
\ is CONDITIONAL(external_resource) since the attacker must also control the external PyPI package\
\ or have registered a typosquat. Also covers envVariables injection (e.g., overriding AIRFLOW__CORE__EXECUTOR\
\ or pointing PYTHONPATH at an attacker-controlled source) and airflowConfigOverrides (can alter scheduler\
\ behavior). Cite can-execute-as execute-as-via-code-modify for the CanExecuteAs collapse (treating\
\ this CanModifyConfiguration as equivalent in effect)."
narrative: '{principal.name} can update Composer environment {env.name} (composer.environments.update)
to add an attacker-controlled Python package to softwareConfig.pypiPackages; the package is installed
on all worker pods and the scheduler and executes at Python import time as the environment SA {sa.name}.
No actAs permission is required for this path (unlike SA-swap updates).'