gcp-tasks-queue-dispatches-to-consumer
A Cloud Tasks queue with httpTarget.uri (or an App Engine target) dispatches tasks to its configured consumer HTTP endpoint - the event-source binding fact consumed by messaging-chains rule 1.
match (record)
{
"field": "httpTarget.uri",
"resource_type": "google.cloud.tasks.v2.Queue"
}
where
queue.httpTarget.uri is set AND resolves to an HTTP/HTTPS endpoint modeled as a Compute consumer (Cloud Run service, Cloud Function, App Engine handler, or
GenericCompute endpoint)
queue.state == RUNNING OR PAUSED (binding is real even if paused)
emit
| source type | Queue |
|---|---|
| target type | Compute |
| source | <Cloud Tasks queue> |
| target | <consumer compute node at httpTarget.uri> |
| conditions | service_state trigger_exists |
| state logic | ACTIVE when queue.state == RUNNING and the consumer endpoint is reachable and registered (Cloud Run service enabled, GCF deployed). CONDITIONAL(service_state) when queue.state == PAUSED — binding is real but dispatch is suspended. CONDITIONAL(trigger_exists) when the consumer endpoint URL resolves to a node that is not currently deployed/enabled. Do not emit for DISABLED queues. |
Narrative
Queue {queue.name} is configured to dispatch HTTP tasks to {consumer.name} (httpTarget.uri = {uri}). A published task reaches {consumer.name} with an attacker-influenced body, forming the event-source binding that messaging-chains rolls into CanTrigger(principal → consumer) when combined with CanWriteData.
Raw rule rules/derived/gcp/tasks.yaml
id: gcp-tasks-queue-dispatches-to-consumer
emits: CanTrigger
description: "A Cloud Tasks queue with httpTarget.uri (or an App Engine target) dispatches tasks to its\
\ configured consumer HTTP endpoint \u2014 the event-source binding fact consumed by messaging-chains\
\ rule 1."
match_record:
resource_type: google.cloud.tasks.v2.Queue
field: httpTarget.uri
where:
- queue.httpTarget.uri is set AND resolves to an HTTP/HTTPS endpoint modeled as a Compute consumer (Cloud
Run service, Cloud Function, App Engine handler, or GenericCompute endpoint)
- queue.state == RUNNING OR PAUSED (binding is real even if paused)
emit:
source_type: Queue
target_type: Compute
source: <Cloud Tasks queue>
target: <consumer compute node at httpTarget.uri>
permissions: []
conditions:
- service_state
- trigger_exists
state_logic: "ACTIVE when queue.state == RUNNING and the consumer endpoint is reachable and registered\
\ (Cloud Run service enabled, GCF deployed). CONDITIONAL(service_state) when queue.state == PAUSED\
\ \u2014 binding is real but dispatch is suspended. CONDITIONAL(trigger_exists) when the consumer\
\ endpoint URL resolves to a node that is not currently deployed/enabled. Do not emit for DISABLED\
\ queues."
derived_from:
- queue.httpTarget.uri field from cloudtasks.queues.get
false_positive_note: "Only emit when httpTarget.uri actually resolves to a modeled Compute node (Cloud\
\ Run service URL, GCF HTTPS trigger URL, App Engine default service URL). An external/non-GCP endpoint\
\ is still a CanTrigger target \u2014 model as GenericCompute and note that ExecutesAs is unknown\
\ for non-GCP consumers. Do NOT emit for queues with appEngineHttpQueue target using a fully blank\
\ routing (the handler is the App Engine default service, which is still a valid consumer \u2014 emit\
\ with target_type ApplicationPlatform). A queue with no httpTarget.uri and no appEngineHttpQueue\
\ is not yet bound to a consumer; do not emit."
narrative: "Queue {queue.name} is configured to dispatch HTTP tasks to {consumer.name} (httpTarget.uri\
\ = {uri}). A published task reaches {consumer.name} with an attacker-influenced body, forming the\
\ event-source binding that messaging-chains rolls into CanTrigger(principal \u2192 consumer) when\
\ combined with CanWriteData."