gcp-bigquery-escalate-via-grant-permission

A principal with bigquery.datasets.setIamPolicy can self-grant roles/bigquery.dataOwner and escalate its data-plane privilege.

derived gcp emits CanEscalateTo

match

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

{'principal': None} CanGrantPermission {'dataset': None}

where

node_type(?dataset) == DataWarehouse # BigQuery Dataset node ?principal.privilege_level < elevated # self-grant yields elevated/admin data access

emit

source typeIdentity
target typeIdentity
source?principal
target?principal
permissionsbigquery.datasets.setIamPolicy
conditionsiam_permission
state logicACTIVE when CanGrantPermission on the dataset is ACTIVE and the self-grant would yield a privilege level above the current one; inherits state from the CanGrantPermission contributor.

Narrative

{principal.name} holds bigquery.datasets.setIamPolicy on {dataset.name} and can grant itself roles/bigquery.dataOwner, escalating to full data-plane access over all tables in {dataset.name}.

Raw rule rules/derived/gcp/bigquery.yaml

id: gcp-bigquery-escalate-via-grant-permission
emits: CanEscalateTo
description: A principal with bigquery.datasets.setIamPolicy can self-grant roles/bigquery.dataOwner and
  escalate its data-plane privilege.
match:
- - principal: null
  - CanGrantPermission
  - dataset: null
where:
- 'node_type(?dataset) == DataWarehouse   # BigQuery Dataset node'
- '?principal.privilege_level < elevated  # self-grant yields elevated/admin data access'
emit:
  source_type: Identity
  target_type: Identity
  source: ?principal
  target: ?principal
  permissions:
  - bigquery.datasets.setIamPolicy
  conditions:
  - iam_permission
  state_logic: ACTIVE when CanGrantPermission on the dataset is ACTIVE and the self-grant would yield
    a privilege level above the current one; inherits state from the CanGrantPermission contributor.
  false_positive_note: Self-escalation via setIamPolicy is only meaningful when the resulting role (e.g.
    roles/bigquery.dataOwner or roles/bigquery.admin) gives the principal more data access than it currently
    holds. If the principal already holds roles/bigquery.admin or equivalent, no escalation. This is a
    data-plane escalation (read/exfiltrate more data), not a management-plane IAM escalation (the setIamPolicy
    is scoped to BigQuery dataset resources, not the project or organization IAM). For full project/org
    privilege escalation the attacker would also need resourcemanager.projects.setIamPolicy (a different
    edge). can-control.yaml escalate-via-execute-as handles the CanExecuteAs path; cite, do not re-derive.
  narrative: '{principal.name} holds bigquery.datasets.setIamPolicy on {dataset.name} and can grant itself
    roles/bigquery.dataOwner, escalating to full data-plane access over all tables in {dataset.name}.'
  derived_from:
  - ?principal CanGrantPermission ?dataset
  - bigquery.datasets.setIamPolicy
move · open · esc close