gcp-firestore-backup-restore-overwrite

datastore.backups.restoreDatabase on a Firestore database + access to a Firestore backup enables restoring the backup, completely overwriting all current database content. Identical attack impact to import but via backup rather than GCS export.

derived gcp emits CanWriteData

match (effective permission)

{ "action": "datastore.backups.restoreDatabase", "resource_type": "google.firestore.Database" }

where

?principal has access (datastore.backups.get or datastore.backups.list) to at least one Firestore Backup resource in the same project

emit

source typeIdentity
target typeData
source<principal>
target<Firestore Database / NoSQLDatabase node>
permissionsdatastore.backups.restoreDatabase
conditionsiam_permission resource_policy
state logicCONDITIONAL(resource_policy) when datastore.backups.restoreDatabase is confirmed effective on the Firestore Database AND the principal can enumerate or access a Firestore Backup (via datastore.backups.get or datastore.backups.list). ACTIVE if the principal controls a backup (created it or has full backup admin rights); the attacker can restore it to overwrite the target database. CONDITIONAL if backup access is uncertain. Restoring a backup completely replaces the current database content with the backup's content at the time of snapshot.

Narrative

{principal.name} holds datastore.backups.restoreDatabase on {database.name} and can enumerate Firestore backups (datastore.backups.get / datastore.backups.list), then restore one to {database.name}, completely overwriting all existing data. This bypasses all document-level write restrictions and constitutes a full CanWriteData capability with identical impact to import-based overwrite.

Raw rule rules/derived/gcp/firestore.yaml

id: gcp-firestore-backup-restore-overwrite
emits: CanWriteData
description: datastore.backups.restoreDatabase on a Firestore database + access to a Firestore backup
  enables restoring the backup, completely overwriting all current database content. Identical attack
  impact to import but via backup rather than GCS export.
match_effective_permission:
  action: datastore.backups.restoreDatabase
  resource_type: google.firestore.Database
where:
- ?principal has access (datastore.backups.get or datastore.backups.list) to at least one Firestore Backup
  resource in the same project
emit:
  source_type: Identity
  target_type: Data
  source: <principal>
  target: <Firestore Database / NoSQLDatabase node>
  permissions:
  - datastore.backups.restoreDatabase
  conditions:
  - iam_permission
  - resource_policy
  state_logic: CONDITIONAL(resource_policy) when datastore.backups.restoreDatabase is confirmed effective
    on the Firestore Database AND the principal can enumerate or access a Firestore Backup (via datastore.backups.get
    or datastore.backups.list). ACTIVE if the principal controls a backup (created it or has full backup
    admin rights); the attacker can restore it to overwrite the target database. CONDITIONAL if backup
    access is uncertain. Restoring a backup completely replaces the current database content with the
    backup's content at the time of snapshot.
  confidence: '0.87'
  derived_from:
  - datastore.backups.restoreDatabase effective permission on Firestore Database
  - datastore.backups.get / datastore.backups.list on Firestore Backup resource
  - gcp-firestore-import-overwrite (analogous pattern)
  false_positive_note: "Backup restore is a bulk, destructive operation equivalent to import: it replaces\
    \ the entire database with the backup snapshot. Document-level IAM permissions do NOT gate restore\
    \ \u2014 a principal with datastore.backups.restoreDatabase can bypass all document-level access controls.\
    \ The attacker must have access to (or be able to enumerate) a Firestore Backup. Backups are scoped\
    \ to a project; a principal with datastore.backups.list at the project scope can enumerate all backups,\
    \ then restore any one to the target database (if they also hold restoreDatabase on that database).\
    \ Point-in-time recovery (PITR) creates automatic backups; a principal with access to enumerate them\
    \ can restore to any snapshot in the retention window. Org policy constraints on database mutations\
    \ may block restore. Note: datastore.backups.restoreDatabase is included in roles/datastore.backupAdmin\
    \ and roles/datastore.owner. Cite gcp-firestore-import-overwrite as the identical risk pattern via\
    \ alternative vector."
  narrative: '{principal.name} holds datastore.backups.restoreDatabase on {database.name} and can enumerate
    Firestore backups (datastore.backups.get / datastore.backups.list), then restore one to {database.name},
    completely overwriting all existing data. This bypasses all document-level write restrictions and
    constitutes a full CanWriteData capability with identical impact to import-based overwrite.'
move · open · esc close