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.

derived gcp emits CrossProjectTrust

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 typeResourcePolicy
target typeProject
source<queue IAM allow policy (ResourcePolicy)>
target<external project of the granted principal>
conditionsresource_policy condition_expression
state logicACTIVE 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.
move · open · esc close