gcp-datastream-stream-create-exfil
datastream.streams.create + datastream.connectionProfiles.create lets a principal create a new CDC stream from an existing source database to an attacker-controlled destination, exfiltrating source data.
match (effective permission)
{
"action": "datastream.streams.create",
"resource_type": "google.datastream.Stream"
}
where
principal also has effective datastream.connectionProfiles.create (to create a destination profile) OR can reference an existing attacker-controlled connection profile
Datastream can reach the source database (via private connection, forward SSH tunnel, or static IP allowlist on the source)
emit
| source type | Identity |
|---|---|
| target type | Data |
| source | <principal> |
| target | <source database data accessible via existing connection profiles> |
| permissions | datastream.streams.create datastream.connectionProfiles.create |
| conditions | iam_permission network_reachability api_enabled |
| state logic | ACTIVE if both permissions are confirmed AND network_reachability to the source DB via Datastream is established (an existing connection profile for the source DB can be referenced, or the source DB is reachable from Datastream's public IPs). CONDITIONAL(network_reachability) if source reachability is unconfirmed. CONDITIONAL(iam_permission) if connectionProfiles.create is missing (must use an existing source connection profile the principal can reference). BLOCKED if a deny policy or VPC Service Controls perimeter blocks either permission. |
Narrative
{principal.name} can create a new Datastream stream (datastream.streams.create) with a new destination connection profile pointing to an attacker-controlled BigQuery dataset or GCS path, replicating data from an accessible source database to that destination. A full backfill exfiltrates the entire source database contents.
Raw rule rules/derived/gcp/datastream.yaml
id: gcp-datastream-stream-create-exfil
emits: CanExfiltrate
description: datastream.streams.create + datastream.connectionProfiles.create lets a principal create
a new CDC stream from an existing source database to an attacker-controlled destination, exfiltrating
source data.
match_effective_permission:
action: datastream.streams.create
resource_type: google.datastream.Stream
where:
- principal also has effective datastream.connectionProfiles.create (to create a destination profile)
OR can reference an existing attacker-controlled connection profile
- Datastream can reach the source database (via private connection, forward SSH tunnel, or static IP allowlist
on the source)
emit:
source_type: Identity
target_type: Data
source: <principal>
target: <source database data accessible via existing connection profiles>
permissions:
- datastream.streams.create
- datastream.connectionProfiles.create
conditions:
- iam_permission
- network_reachability
- api_enabled
state_logic: ACTIVE if both permissions are confirmed AND network_reachability to the source DB via
Datastream is established (an existing connection profile for the source DB can be referenced, or
the source DB is reachable from Datastream's public IPs). CONDITIONAL(network_reachability) if source
reachability is unconfirmed. CONDITIONAL(iam_permission) if connectionProfiles.create is missing (must
use an existing source connection profile the principal can reference). BLOCKED if a deny policy or
VPC Service Controls perimeter blocks either permission.
confidence: 0.85
derived_from:
- <datastream.streams.create effective permission>
- <datastream.connectionProfiles.create effective permission (if present)>
false_positive_note: Creating a stream requires a SOURCE connection profile (the database the stream
reads from). If the principal cannot create a new source profile AND cannot reference an existing
one that points to a reachable database, no new exfil stream can be established. Do NOT emit ACTIVE
if there are no reachable source connection profiles. Also requires datastream.streams.start to actually
begin replication; if the principal lacks streams.start, the stream is created but paused (CONDITIONAL).
This is a slightly weaker path than streams.update (which hijacks an existing stream's output); prefer
streams.update rules for running streams.
narrative: '{principal.name} can create a new Datastream stream (datastream.streams.create) with a new
destination connection profile pointing to an attacker-controlled BigQuery dataset or GCS path, replicating
data from an accessible source database to that destination. A full backfill exfiltrates the entire
source database contents.'