gcp-tasks-uri-override-token-capture

Setting httpTarget.uriOverride to an attacker-controlled endpoint (via cloudtasks.queues.update, no actAs needed) redirects all future dispatches there - delivering the queue's OIDC/OAuth SA token and task body payloads to the attacker.

derived gcp emits ExposesCredential

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

?principal CanModifyConfiguration ?queue ?queue ExposesCredential ?sa

where

node_type(?queue) == Queue AND provider_type(?queue) == google.cloud.tasks.v2.Queue ?queue.httpTarget.oidcToken.serviceAccountEmail is non-empty (queue has an OIDC SA) ?principal can set httpTarget.uriOverride via cloudtasks.queues.update

emit

source typeMessaging
target typeIdentity
source<Cloud Tasks queue (Messaging)>
target<configured OIDC/OAuth SA>
permissionscloudtasks.queues.update
conditionsiam_permission trigger_exists
state logicACTIVE when the principal has cloudtasks.queues.update on the queue AND the queue has an OIDC/OAuth SA configured AND the queue state is RUNNING (or can be resumed). CONDITIONAL(trigger_exists) when the queue is PAUSED or no tasks are scheduled — the redirect is in place but tokens are only delivered when dispatch occurs. No actAs is required to set uriOverride — this is the barrier-free token-capture path.

Narrative

{principal.name} can update {queue.name}'s httpTarget.uriOverride to an attacker-controlled endpoint (cloudtasks.queues.update, no actAs needed). All future dispatches redirect there, delivering the OIDC/OAuth token for {sa.name} and task body payloads - capturing short-lived {sa.name} credentials.

Raw rule rules/derived/gcp/tasks.yaml

id: gcp-tasks-uri-override-token-capture
emits: ExposesCredential
description: "Setting httpTarget.uriOverride to an attacker-controlled endpoint (via cloudtasks.queues.update,\
  \ no actAs needed) redirects all future dispatches there \u2014 delivering the queue's OIDC/OAuth SA\
  \ token and task body payloads to the attacker."
match:
- - ?principal
  - CanModifyConfiguration
  - ?queue
- - ?queue
  - ExposesCredential
  - ?sa
where:
- node_type(?queue) == Queue AND provider_type(?queue) == google.cloud.tasks.v2.Queue
- ?queue.httpTarget.oidcToken.serviceAccountEmail is non-empty (queue has an OIDC SA)
- ?principal can set httpTarget.uriOverride via cloudtasks.queues.update
emit:
  source_type: Messaging
  target_type: Identity
  source: <Cloud Tasks queue (Messaging)>
  target: <configured OIDC/OAuth SA>
  permissions:
  - cloudtasks.queues.update
  conditions:
  - iam_permission
  - trigger_exists
  state_logic: "ACTIVE when the principal has cloudtasks.queues.update on the queue AND the queue has\
    \ an OIDC/OAuth SA configured AND the queue state is RUNNING (or can be resumed). CONDITIONAL(trigger_exists)\
    \ when the queue is PAUSED or no tasks are scheduled \u2014 the redirect is in place but tokens are\
    \ only delivered when dispatch occurs. No actAs is required to set uriOverride \u2014 this is the\
    \ barrier-free token-capture path."
  confidence: min(contributing_confidences) * 0.95
  derived_from:
  - ?principal CanModifyConfiguration ?queue (gcp-tasks-update-queue-config)
  - ?queue ExposesCredential ?sa (gcp-tasks-queue-exposes-oidc-sa)
  false_positive_note: "httpTarget.uriOverride only affects HTTP target queues \u2014 not App Engine queues.\
    \ The redirect captures the token at delivery time; the attacker must control an HTTPS endpoint to\
    \ receive the dispatch. Org policy constraints/cloudtasks.allowedIngress may restrict which URI schemes/hosts\
    \ are permitted as httpTarget values \u2014 check org policy before marking ACTIVE. This edge expresses\
    \ the token-capture capability; the CanReadSecret consequence (the captured token is CredentialsFor\
    \ the SA) is handled by credential-chains."
  narrative: "{principal.name} can update {queue.name}'s httpTarget.uriOverride to an attacker-controlled\
    \ endpoint (cloudtasks.queues.update, no actAs needed). All future dispatches redirect there, delivering\
    \ the OIDC/OAuth token for {sa.name} and task body payloads \u2014 capturing short-lived {sa.name}\
    \ credentials."
move · open · esc close