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