Skip to content

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:

match /users/{userId} {
  allow read, write: if request.auth != null;
}

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:

match /orders/{orderId} {
  allow read: if request.auth != null;
}

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 {
    // VULNERABLE: Only checks authentication, not authorization
    match /users/{userId} {
      allow read, write: if request.auth != null;
    }

    match /orders/{orderId} {
      allow read: if request.auth != null;
    }
  }
}
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:

  1. Authentication Check (request.auth != null): Ensures someone is logged in
  2. Authorization Check (request.auth.uid == userId or resource.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.

References