Firebase Security Vulnerability: FBR-AUTHZ-001¶
Name: Firestore Insecure Direct Object Reference (IDOR) Vulnerability
Applicable Services: Cloud Firestore, Firebase Realtime Database
Description¶
Technical Vulnerability Overview
The Technical Flaw: Security rules that only check request.auth != null
without verifying user-specific authorization create an Insecure Direct Object Reference (IDOR) vulnerability. The rule confirms a user is authenticated but doesn't validate if that user should access the specific resource.
Intended Behavior: Firebase security rules should implement both authentication (is someone logged in?) and authorization (is this specific user allowed to access this specific resource?).
The Risk: Any authenticated user can access or modify data belonging to other users by manipulating document paths or IDs in their requests, leading to complete breakdown of user data isolation.
Impact¶
Potential Consequences
This vulnerability can lead to severe security breaches:
- Complete Data Exfiltration: Attackers can systematically harvest all user data by iterating through predictable document IDs
- Unauthorized Data Modification: Malicious users can modify or delete other users' personal information, settings, or application data
- Privacy Violations: Sensitive personal information becomes accessible to any authenticated user in the application
- Compliance Violations: Breach of data protection regulations like GDPR, CCPA, or HIPAA due to inadequate access controls
- Reputation Damage: Loss of user trust and potential legal liability from data breaches
Example Attack Scenarios¶
Exploit Scenario: User Profile Data Theft
The Vulnerable Rule:
Attacker's Goal: To access and steal personal profile data from other users in the application.
The Exploit: An authenticated attacker (user ID: attacker-123
) uses this JavaScript code to access another user's profile:
// The attacker is logged in as 'attacker-123' but requests victim's data
const victimProfile = await db.collection('users').doc('victim-456').get();
if (victimProfile.exists) {
const stolenData = victimProfile.data();
console.log('Stolen user data:', stolenData);
// Attacker now has access to victim's personal information
}
Outcome: The attacker successfully retrieves the victim's personal profile data including email, phone number, preferences, and any other stored information.
Exploit Scenario: Systematic Data Harvesting
The Vulnerable Rule:
Attacker's Goal: To systematically harvest all order data from the application.
The Exploit: The attacker uses predictable document IDs to iterate through all orders:
// Systematic harvesting of all order data
const harvestedOrders = [];
for (let i = 1; i <= 10000; i++) {
try {
const orderDoc = await db.collection('orders').doc(`order-${i}`).get();
if (orderDoc.exists) {
harvestedOrders.push(orderDoc.data());
}
} catch (error) {
// Continue to next ID
}
}
console.log(`Harvested ${harvestedOrders.length} orders with sensitive data`);
Outcome: The attacker obtains a comprehensive database of all order information, including customer details, purchase history, and payment information.
Mitigation¶
The vulnerability is resolved by adding a specific authorization check to the security rule. It's not enough to check if a user is authenticated; you must verify they have permission to access the specific document requested.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// SECURE: Checks both authentication AND authorization
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
// For collections with owner fields, check the field value
match /orders/{orderId} {
allow read: if request.auth != null && resource.data.ownerId == request.auth.uid;
allow write: if request.auth != null && request.resource.data.ownerId == request.auth.uid;
}
}
}
Security Best Practice
The secure rule works by combining two essential checks:
- Authentication Check (
request.auth != null
): Ensures someone is logged in - Authorization Check (
request.auth.uid == userId
orresource.data.ownerId == request.auth.uid
): Ensures the logged-in user owns or has permission to access the specific resource
This pattern ensures complete user data isolation and prevents IDOR vulnerabilities.