gcp-firestore-import-overwrite
datastore.databases.import + control of a source GCS bucket enables importing a Firestore export, overwriting ALL existing data in the database (bypass document-level write controls).
match (effective permission)
{
"action": "datastore.databases.import",
"resource_type": "google.firestore.Database"
}
where
?principal ALSO has EFFECTIVE storage.objects.get on a source GCS bucket (attacker-controlled or writable by the principal)
emit
| source type | Identity |
|---|---|
| target type | Data |
| source | <principal> |
| target | <Firestore Database / NoSQLDatabase node> |
| permissions | datastore.databases.import storage.objects.get |
| conditions | iam_permission resource_policy |
| state logic | CONDITIONAL(resource_policy) when datastore.databases.import is confirmed effective on the Firestore Database AND the principal controls (or has read access to) a GCS bucket containing a Firestore export file. The attacker must also have created or gained control of the import source. ACTIVE if source bucket is confirmed attacker-controlled; CONDITIONAL if the source bucket is internal and the attacker must first populate it (e.g., via CanExfiltrate). This is an extremely disruptive action (replaces ALL database content); real attackers use it for data destruction or to inject a full attacker-controlled dataset. |
Narrative
{principal.name} holds datastore.databases.import on {database.name} and can import a Firestore export from a GCS bucket it controls (storage.objects.get), completely overwriting all existing data in the database. This bypasses all document-level write restrictions and constitutes a full CanWriteData capability (though extremely loud and destructive - suitable for data poisoning or erasure).
Raw rule rules/derived/gcp/firestore.yaml
id: gcp-firestore-import-overwrite
emits: CanWriteData
description: datastore.databases.import + control of a source GCS bucket enables importing a Firestore
export, overwriting ALL existing data in the database (bypass document-level write controls).
match_effective_permission:
action: datastore.databases.import
resource_type: google.firestore.Database
where:
- ?principal ALSO has EFFECTIVE storage.objects.get on a source GCS bucket (attacker-controlled or writable
by the principal)
emit:
source_type: Identity
target_type: Data
source: <principal>
target: <Firestore Database / NoSQLDatabase node>
permissions:
- datastore.databases.import
- storage.objects.get
conditions:
- iam_permission
- resource_policy
state_logic: CONDITIONAL(resource_policy) when datastore.databases.import is confirmed effective on
the Firestore Database AND the principal controls (or has read access to) a GCS bucket containing
a Firestore export file. The attacker must also have created or gained control of the import source.
ACTIVE if source bucket is confirmed attacker-controlled; CONDITIONAL if the source bucket is internal
and the attacker must first populate it (e.g., via CanExfiltrate). This is an extremely disruptive
action (replaces ALL database content); real attackers use it for data destruction or to inject a
full attacker-controlled dataset.
confidence: '0.85'
derived_from:
- datastore.databases.import effective permission on Firestore Database
- storage.objects.get on source GCS bucket
false_positive_note: "Import is a bulk, destructive operation: it replaces the entire database. Document-level\
\ IAM permissions (datastore.entities.* create/update) do NOT gate import \u2014 a principal with\
\ datastore.databases.import can bypass all document-level access controls. However, the attacker\
\ must control or compromise the SOURCE bucket (which holds the export file to import). Emit CONDITIONAL(resource_policy)\
\ to indicate the resource-policy gate on the source bucket. Escalation assumes the attacker has (1)\
\ CanExfiltrate to create a malicious export or (2) access to an existing export. Org policy constraints\
\ on database mutations may block import. Note: import is included in roles/datastore.importExportAdmin\
\ and roles/datastore.owner."
narrative: "{principal.name} holds datastore.databases.import on {database.name} and can import a Firestore\
\ export from a GCS bucket it controls (storage.objects.get), completely overwriting all existing\
\ data in the database. This bypasses all document-level write restrictions and constitutes a full\
\ CanWriteData capability (though extremely loud and destructive \u2014 suitable for data poisoning\
\ or erasure)."