← All field notes
gcpbigqueryfor security teams

The BigQuery schedule that exfiltrates long after the attacker leaves

A rogue BigQuery scheduled query runs as a service account and exports sensitive rows on every interval. Cancelling one run does nothing; you must delete the saved schedule.

Most data theft is a single grab. A scheduled query is different: it is persistence, quietly exfiltrating on its own interval long after the attacker has logged off.

How the attack works

The attacker creates a BigQuery scheduled query, which is a data-transfer config, that selects new rows from a sensitive table on a recurring interval. It is configured to execute as a service account, decoupling it from the creator’s session. The first run writes selected rows to an attacker-owned dataset or Cloud Storage bucket, and a second run on the next interval confirms autonomous, ongoing exfiltration. Unlike a one-off query, the schedule survives and re-runs itself. The audit trail lives in the bigquerydatatransfer transferConfigs.create entry and the per-run BigQuery job and Data Access logs under the runner service account. This maps to T1537, Transfer Data to Cloud Account, and T1648, Serverless Execution.

Why it works

Broad rights let the attacker create transfer configs and bind a powerful service account, and nothing alerts on new schedules. Because scheduled queries are routine for reporting and ETL, the backdoor blends in.

How to fix it

Cancelling the currently running job is the trap: the schedule is intact, so it simply fires again at the next interval. The real containment is to find and delete the rogue scheduled query, the transfer config, so it cannot fire again, then scope or disable the runner service account so it loses both the schedule and the access. Because it recurred, impact is cumulative, so sum the rows exported across every run from the job logs over the full active duration. Durably, restrict who can create transfer configs, scope runnable service accounts to least privilege, and alert on new schedules and external exports.

Practice it

We built this as a GraphLattice Range scenario so security teams learn to delete the saved schedule, not just the run, and to total every interval.