In Cloud Composer, writing a DAG file is running code as a service account
Drop a Python file in the Composer DAGs bucket and Airflow runs it as the environment service account. Deleting one object is not enough. Here is durable containment.
Cloud Composer runs Airflow, and any Python file dropped in the DAGs bucket becomes code that executes as the environment service account. Writing a file is the same as running code.
How the attack works
An attacker with write access to the DAGs bucket uploads a malicious Python DAG. Cloud Audit Logs record a storage.objects.create on the bucket from a principal that is not the known deployer identity. The Airflow scheduler parses the new file and queues a task to a worker, which executes it with the environment service account’s identity and IAM permissions. The task enumerates buckets, reads objects from a sensitive bucket, and writes them to an attacker-reachable destination, all under the service account. In ATT&CK terms this is T1648, Serverless Execution, with T1059, Command and Scripting Interpreter, and T1078.004, Valid Accounts: Cloud Accounts.
Why it works
The Composer service account held broad project permissions, and the DAGs bucket allowed wide write access. The scheduler re-scans the bucket continuously, so any writer becomes a code-execution path as a possibly over-privileged identity.
How to fix it
Deleting one object is not durable, because the scheduler re-parses the bucket on a loop and a re-upload runs again. Pause and delete the rogue DAG, remove the object, then restrict write IAM on the DAGs bucket to the controlled deployer identity and scope the Composer service account to least privilege so even a re-upload cannot run with broad rights. Scope what actually ran from Cloud Audit Logs filtered to the Composer service account plus GCS Data Access logs, since the DAG source shows intent, not activity.
Practice it
We built this as a GraphLattice Range scenario so teams can rehearse the write-equals-execute path, the close-the-write-path containment, and the least-privilege fix.