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).

derived gcp emits CanWriteData

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 typeIdentity
target typeData
source<principal>
target<Firestore Database / NoSQLDatabase node>
permissionsdatastore.databases.import storage.objects.get
conditionsiam_permission resource_policy
state logicCONDITIONAL(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)."
move · open · esc close