gcp-tasks-cross-project-enqueue-trust
A Cloud Tasks queue IAM policy granting cloudtasks.tasks.create to a principal from another GCP project is cross-project messaging trust - the foreign principal can publish tasks to trigger the queue's consumer in the queue's project.
match (record)
{
"field": "iamPolicy.bindings",
"resource_type": "google.cloud.tasks.v2.Queue"
}
where
a binding member (user:, serviceAccount:) belongs to a different project than the queue resource
the binding grants cloudtasks.tasks.create (roles/cloudtasks.enqueuer or roles/cloudtasks.admin)
emit
| source type | ResourcePolicy |
|---|---|
| target type | Project |
| source | <queue IAM allow policy (ResourcePolicy)> |
| target | <external project of the granted principal> |
| conditions | resource_policy condition_expression |
| state logic | ACTIVE when the binding unconditionally grants cloudtasks.tasks.create to an external principal. CONDITIONAL(condition_expression) when scoped by an IAM condition (resource tag, request time, originating IP). BLOCKED by an org policy or IAM deny that overrides the grant. On GCP this emits CrossProjectTrust (Project target) per messaging-chains rule 4 guidance. |
Narrative
The IAM policy of queue {queue.name} grants a principal in project {ext_project.name} the ability to create tasks (cloudtasks.tasks.create), establishing cross-project trigger trust; an attacker in that project can publish tasks to {queue.name} to drive its consumer with an attacker-controlled payload.
Raw rule rules/derived/gcp/tasks.yaml
id: gcp-tasks-cross-project-enqueue-trust
emits: CrossProjectTrust
description: "A Cloud Tasks queue IAM policy granting cloudtasks.tasks.create to a principal from another\
\ GCP project is cross-project messaging trust \u2014 the foreign principal can publish tasks to trigger\
\ the queue's consumer in the queue's project."
match_record:
resource_type: google.cloud.tasks.v2.Queue
field: iamPolicy.bindings
where:
- a binding member (user:, serviceAccount:) belongs to a different project than the queue resource
- the binding grants cloudtasks.tasks.create (roles/cloudtasks.enqueuer or roles/cloudtasks.admin)
emit:
source_type: ResourcePolicy
target_type: Project
source: <queue IAM allow policy (ResourcePolicy)>
target: <external project of the granted principal>
permissions: []
conditions:
- resource_policy
- condition_expression
state_logic: ACTIVE when the binding unconditionally grants cloudtasks.tasks.create to an external principal.
CONDITIONAL(condition_expression) when scoped by an IAM condition (resource tag, request time, originating
IP). BLOCKED by an org policy or IAM deny that overrides the grant. On GCP this emits CrossProjectTrust
(Project target) per messaging-chains rule 4 guidance.
derived_from:
- "queue.iamPolicy.bindings \u2014 cross-project member with cloudtasks.tasks.create"
false_positive_note: "CITE, DO NOT DUPLICATE can-control: this rule asserts ONLY the cross-project messaging\
\ trust fact \u2014 it does NOT emit CanEnterProject. The CanEnterProject consequence (external principal\
\ publishes task \u2192 triggers consumer in the queue's project \u2192 CanExecuteAs consumer runtime\
\ SA) is produced by can-control consuming this CrossProjectTrust together with CanWriteData / CanTrigger\
\ / ExecutesAs from messaging-chains rules 1-2. Honor IAM conditions that narrow the grant. A grant\
\ to cloudtasks.queues.update (admin-level) from another project is a stronger trust fact \u2014 emit\
\ CrossProjectTrust with a note about the elevated permission scope."
narrative: The IAM policy of queue {queue.name} grants a principal in project {ext_project.name} the
ability to create tasks (cloudtasks.tasks.create), establishing cross-project trigger trust; an attacker
in that project can publish tasks to {queue.name} to drive its consumer with an attacker-controlled
payload.