gcp-bigquery-explicit-cross-project-trust

A dataset ACL entry naming a dataset, view, or SA from another project grants cross-project data read access - a BigQuery-native cross-project trust.

explicit gcp emits CrossProjectTrust

match (record)

{ "field": "access[].dataset | access[].userByEmail (cross-project SA)", "resource_type": "google.bigquery.Dataset" }

where

ACL entry references a dataset, view, or SA whose project != the source dataset's project

emit

source typeProject
target typeProject
source<project owning the source dataset>
target<foreign project owning the authorized dataset/view/SA>
conditionsresource_policy
state logicACTIVE when the authorized dataset or cross-project SA entry is present in the access[] array; CONDITIONAL(resource_policy) when the entry exists but the foreign principal's IAM cannot be confirmed.

Narrative

Dataset {dataset.name} (project {projectA.name}) grants cross-project data access to a principal in project {projectB.name} via an authorized dataset or cross-project ACL entry; {projectB.name} can read {dataset.name} tables without holding IAM bindings in project {projectA.name}.

Raw rule rules/explicit/gcp/bigquery.yaml

id: gcp-bigquery-explicit-cross-project-trust
emits: CrossProjectTrust
description: "A dataset ACL entry naming a dataset, view, or SA from another project grants cross-project\
  \ data read access \u2014 a BigQuery-native cross-project trust."
match_record:
  resource_type: google.bigquery.Dataset
  field: access[].dataset | access[].userByEmail (cross-project SA)
where:
- ACL entry references a dataset, view, or SA whose project != the source dataset's project
emit:
  source_type: Project
  target_type: Project
  source: <project owning the source dataset>
  target: <foreign project owning the authorized dataset/view/SA>
  permissions: []
  conditions:
  - resource_policy
  state_logic: ACTIVE when the authorized dataset or cross-project SA entry is present in the access[]
    array; CONDITIONAL(resource_policy) when the entry exists but the foreign principal's IAM cannot be
    confirmed.
  false_positive_note: "Authorized views / authorized datasets (access[].dataset entries) grant the DATASET\
    \ in project B read-only access to the source dataset in project A WITHOUT requiring direct IAM bindings\
    \ in project A for the views' users. This is a data trust, not a management-plane trust. An attacker\
    \ who controls project B's dataset can create views that read project A's tables. This edge does NOT\
    \ allow cross-project IAM escalation \u2014 only data-plane read of the authorized tables. Authorized\
    \ views CANNOT EXPORT data (EXPORT DATA fails without getData + storage.objects.create held by the\
    \ querying principal independently). Cross-project SA entries (access[].userByEmail = SA from another\
    \ project) grant that SA READER/WRITER/OWNER access in the source dataset \u2014 a broader trust."
  narrative: Dataset {dataset.name} (project {projectA.name}) grants cross-project data access to a principal
    in project {projectB.name} via an authorized dataset or cross-project ACL entry; {projectB.name} can
    read {dataset.name} tables without holding IAM bindings in project {projectA.name}.
  derived_from:
  - google.bigquery.Dataset.access[] cross-project entry
  api_source: bigquery.datasets.get (access[] array)
  evidence_field: access[].dataset.projectId or cross-project SA email
move · open · esc close