gcp-firestore-explicit-cross-project-trust
A Firestore database IAM binding granting any role to a principal in a different GCP project is a cross-project trust on the database's data.
match (record)
{
"api": "firestore.projects.databases.getIamPolicy",
"field": "iamPolicy.bindings[].members",
"resource_type": "google.firestore.Database"
}
where
a member (serviceAccount / user / group) belongs to a different GCP project than the database
emit
| source type | Project |
|---|---|
| target type | Project |
| source | <database's project> |
| target | <foreign project the member belongs to> |
| conditions | resource_policy |
| state logic | ACTIVE when the cross-project binding is present in the effective IAM policy at the project or database scope; CONDITIONAL(resource_policy) when the foreign principal's own IAM cannot be confirmed. |
Narrative
Firestore database {database.name} (project {projectA.name}) grants data access to a principal in project {projectB.name} via an IAM binding; {projectB.name} can read/write Firestore documents without holding IAM bindings independently in project {projectA.name}.
Raw rule rules/explicit/gcp-firestore.yaml
id: gcp-firestore-explicit-cross-project-trust
emits: CrossProjectTrust
description: A Firestore database IAM binding granting any role to a principal in a different GCP project
is a cross-project trust on the database's data.
match_record:
api: firestore.projects.databases.getIamPolicy
resource_type: google.firestore.Database
field: iamPolicy.bindings[].members
where:
- a member (serviceAccount / user / group) belongs to a different GCP project than the database
emit:
source_type: Project
target_type: Project
source: <database's project>
target: <foreign project the member belongs to>
permissions: []
conditions:
- resource_policy
state_logic: ACTIVE when the cross-project binding is present in the effective IAM policy at the project
or database scope; CONDITIONAL(resource_policy) when the foreign principal's own IAM cannot be confirmed.
confidence: '0.94'
derived_from:
- google.firestore.Database iamPolicy.bindings[].members (cross-project principal)
false_positive_note: "A cross-project SA bound to roles/datastore.viewer means a principal from project\
\ B can read documents in project A's Firestore database \u2014 a deliberate but potentially over-broad\
\ trust. The SA must also be usable by an attacker (hold iam.serviceAccounts.actAs or be compromised\
\ independently). GCP-managed service agents (service-PROJECT_NUMBER@gcp-sa-*.iam) are expected and\
\ should be de-prioritized. Flag only when the member is a non-service-agent SA, human user, or external\
\ domain in a different project. Firestore project-level IAM bindings cover ALL databases in the project;\
\ database-level bindings are scoped to a single database. Note whether the binding is project-level\
\ or database-level."
narrative: Firestore database {database.name} (project {projectA.name}) grants data access to a principal
in project {projectB.name} via an IAM binding; {projectB.name} can read/write Firestore documents
without holding IAM bindings independently in project {projectA.name}.