HIGH api key exposurefirebase

Api Key Exposure on Firebase

How Api Key Exposure Manifests in Firebase

Firebase API key exposure in Firebase applications occurs through several Firebase-specific mechanisms that developers often misunderstand. Unlike traditional API keys that should remain secret, Firebase API keys are client-side credentials designed to be public. However, this public nature creates unique security challenges when combined with Firebase's authentication and database access patterns.

The most common Firebase API key exposure scenario involves misconfigured security rules. Developers often hardcode API keys in client applications and assume Firebase's security model will protect them. Consider this typical Firebase initialization pattern:

const firebaseConfig = {
  apiKey: 'AIzaSyD4f8b9c0e1a2b3c4d5e6f7g8h9i0j1k2l3m',
  authDomain: 'your-app.firebaseapp.com',
  databaseURL: 'https://your-app.firebaseio.com',
  projectId: 'your-app',
  storageBucket: 'your-app.appspot.com',
  messagingSenderId: '123456789',
  appId: '1:123456789:web:abcdef1234567890'
};

firebase.initializeApp(firebaseConfig);

This code appears in web applications, mobile apps, and even server-side code. The API key is embedded directly in the client bundle, making it trivially extractable through browser DevTools or APK decompilation.

The critical security issue isn't the API key exposure itself, but what happens when developers combine exposed keys with overly permissive security rules. A common pattern is:

rules_version = '2';

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

// OR using the deprecated Realtime Database rules
{
  "rules": {
    ".read": true,
    ".write": true
  }
}

These rules allow anyone with a valid Firebase API key to read and write to your database. Since the API key is already exposed in client code, this effectively creates an open database accessible to anyone who inspects your application.

Another Firebase-specific exposure vector is the use of anonymous authentication with default security rules. Developers often implement:

firebase.auth().signInAnonymously()
  .then((result) => {
    // User is signed in anonymously
    const user = result.user;
    // Proceed with database operations
  })
  .catch((error) => {
    // Handle errors
  });

When combined with permissive rules like allow read, write: if request.auth != null;, this allows any anonymous user to access data, creating a significant attack surface.

Firebase Storage also presents unique exposure risks. Developers often configure storage buckets with overly permissive rules:

rules_version = '2';

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read: if true;
      allow write: if true;
    }
  }
}

This allows anyone with the Firebase API key to upload, download, or delete files in your storage bucket, potentially leading to data exfiltration, malware distribution, or service abuse.

Firebase-Specific Detection

Detecting Firebase API key exposure requires understanding Firebase's unique architecture and security model. Traditional API key scanning tools often miss Firebase-specific issues because they don't understand Firebase's client-side authentication model.

middleBrick's Firebase-specific scanning identifies several key indicators of API key exposure and misconfiguration. The scanner examines your application for Firebase configuration objects and analyzes the security rules associated with your Firebase project.

Key detection patterns include:

Configuration Object Detection

The scanner identifies Firebase configuration objects in your application code, looking for patterns like:

const firebaseConfig = {
  apiKey: '...', // Exposed API key
  authDomain: '...', // Firebase domain
  databaseURL: '...', // Database endpoint
  projectId: '...', // Project identifier
  storageBucket: '...', // Storage bucket
  messagingSenderId: '...', // Messaging ID
  appId: '...' // Application ID
};

middleBrick extracts these configurations and cross-references them with your Firebase project settings to identify potential security misconfigurations.

Security Rules Analysis

The scanner analyzes your Firebase security rules for overly permissive configurations. It specifically looks for:

  • Rules allowing read, write: if true or equivalent permissive conditions
  • Anonymous authentication rules that allow access without proper validation
  • Storage rules with allow read: if true or allow write: if true
  • Missing authentication checks in Firestore rules
  • Wildcard rules that match all documents or paths

Runtime API Key Validation

middleBrick performs active testing to validate API key functionality and identify what operations are permitted. This includes:

// Testing Firestore read access
const db = firebase.firestore();
db.collection('users').get()
  .then(snapshot => {
    // If this succeeds without authentication, rules are too permissive
  });

The scanner attempts various operations to determine the actual security posture of your Firebase deployment, mapping findings to OWASP API Top 10 categories like Broken Object Level Authorization (BOLA) and Excessive Data Exposure.

Anonymous Authentication Testing

middleBrick tests for anonymous authentication vulnerabilities by attempting to sign in anonymously and perform operations:

firebase.auth().signInAnonymously()
  .then(() => {
    // Test what operations are allowed for anonymous users
    return firebase.firestore().collection('sensitive-data').get();
  })
  .catch(error => {
    // Handle authentication errors
  });

This active testing reveals whether your Firebase project allows anonymous users to access sensitive data.

Firebase-Specific Remediation

Remediating Firebase API key exposure requires a multi-layered approach that leverages Firebase's native security features. The goal isn't to hide the API key (which is impossible in client applications) but to ensure it cannot be used maliciously.

Implement Proper Security Rules

The foundation of Firebase security is proper security rules. Replace permissive rules with authentication-based and data-specific rules:

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow authenticated users to read public data
    match /public/{document=**} {
      allow read: if request.auth != null;
      allow write: if false;
    }
    
    // Allow users to access their own data
    match /users/{userId}/{document=**} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
    
    // Admin-only collections
    match /admin/{document=**} {
      allow read, write: if request.auth.token.admin == true;
    }
  }
}

// Storage rules
rules_version = '2';

service firebase.storage {
  match /b/{bucket}/o {
    // Allow authenticated users to read public files
    match /public/{allPaths=**} {
      allow read: if request.auth != null;
      allow write: if false;
    }
    
    // User-specific storage
    match /users/{userId}/{allPaths=**} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
  }
}

Validate API Key Usage

Firebase allows you to restrict API key usage to specific domains and applications. Configure these restrictions in the Firebase Console:

// In Firebase Console > Project Settings > Service Accounts
// Restrict API key to specific domains:
// - yourdomain.com
// - www.yourdomain.com
// - localhost for development

// For mobile apps, restrict to specific iOS bundle IDs and Android package names

Implement Server-Side Validation

For sensitive operations, use Cloud Functions to validate requests before they reach your database:

// Cloud Function to validate data before writing to Firestore
const functions = require('firebase-functions');
const admin = require('firebase-admin');

exports.validateUserData = functions.https.onCall((data, context) => {
  // Check authentication
  if (!context.auth) {
    throw new functions.https.HttpsError(
      'unauthenticated',
      'User must be authenticated'
    );
  }
  
  // Validate data structure
  if (!data.email || !data.name) {
    throw new functions.https.Https.HttpsError(
      'invalid-argument',
      'Email and name are required'
    );
  }
  
  // Validate email format
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!emailRegex.test(data.email)) {
    throw new functions.https.Https.HttpsError(
      'invalid-argument',
      'Invalid email format'
    );
  }
  
  // Return validated data for Firestore write
  return {
    success: true,
    data: {
      email: data.email,
      name: data.name,
      userId: context.auth.uid
    }
  };
});

Use Custom Claims for Authorization

Implement role-based access control using custom claims:

// Set custom claims for admin users
admin.auth().setCustomUserClaims(uid, { admin: true })
  .then(() => {
    console.log('Admin claims set for user:', uid);
  });

// Security rules using custom claims
match /admin/{document=**} {
  allow read, write: if request.auth.token.admin == true;
}

Monitor and Audit

Enable Firebase Audit Logging to monitor API key usage and detect suspicious patterns:

// Cloud Function to log suspicious activity
exports.logSuspiciousActivity = functions.firestore
  .document('sensitive-data/{docId}')
  .onWrite((change, context) => {
    const before = change.before.data();
    const after = change.after.data();
    
    // Check for unusual data patterns
    if (after && after.sensitiveField) {
      console.log('Suspicious data written:', {
        userId: context.auth.uid,
        documentId: context.params.docId,
        data: after
      });
    }
  });

Frequently Asked Questions

If Firebase API keys are meant to be public, what's the actual security risk?
The API key itself isn't the security risk—it's the combination of exposed keys with permissive security rules. Firebase API keys are client-side credentials that enable access to your Firebase services. The real vulnerability occurs when developers combine these exposed keys with overly permissive security rules (like allow read, write: if true), effectively creating an open database. The API key enables the connection, but the security rules determine what operations are allowed. middleBrick scans for both exposed keys and permissive rules to identify the complete attack surface.
How does middleBrick's Firebase scanning differ from traditional API security tools?
Traditional API security tools often miss Firebase-specific vulnerabilities because they don't understand Firebase's client-side authentication model. middleBrick's Firebase scanning is specifically designed to identify Firebase configuration objects, analyze security rules, and perform active testing of Firebase-specific authentication patterns. It tests for anonymous authentication vulnerabilities, validates security rule permissions, and identifies overly permissive storage configurations. The scanner also maps findings to Firebase-specific security best practices and OWASP API Top 10 categories relevant to NoSQL database security.