MEDIUM use after freefirestore

Use After Free in Firestore

How Use After Free Manifests in Firestore

Use After Free (UAF) in Firestore typically occurs when application logic assumes a document or reference remains valid after deletion or modification, but the Firestore client continues to hold references that can be exploited. This manifests in several Firestore-specific patterns:

// Vulnerable pattern: using stale document reference after deletion
const userDoc = db.collection('users').doc(userId);
const user = await userDoc.get();
// User is deleted by another process
await userDoc.delete();
// Code still uses 'user' object assuming it's valid
console.log(user.data().email); // Data may be stale or lead to logic errors

The most common Firestore UAF scenario involves document references that become invalid after deletion but are still accessed in application logic. Consider this race condition:

// Race condition vulnerability
const docRef = db.collection('orders').doc(orderId);
const doc = await docRef.get();
// Another process deletes the order
await docRef.delete();
// Application logic continues using deleted document
processOrder(doc.data()); // May process invalid data

Firestore's real-time listeners create additional UAF opportunities:

// Real-time listener UAF vulnerability
const unsubscribe = db.collection('chats')
  .doc(chatId)
  .collection('messages')
  .onSnapshot((snapshot) => {
    snapshot.docChanges().forEach((change) => {
      const message = change.doc;
      // Message deleted during iteration
      if (change.type === 'removed') {
        processDeletedMessage(message.data()); // Using freed reference
      }
    });
  });

Transaction isolation can also create UAF-like conditions when documents are modified between read and write operations:

// Transaction UAF pattern
const transaction = async (t) => {
  const docRef = db.collection('inventory').doc(itemId);
  const doc = await t.get(docRef);
  
  // Document deleted by another transaction
  await t.delete(docRef);
  
  // Still using doc reference assuming it's valid
  const newStock = doc.data().stock - quantity;
  t.update(docRef, { stock: newStock }); // Fails silently or throws
};
await db.runTransaction(transaction);

Firestore-Specific Detection

Detecting Use After Free in Firestore requires examining both code patterns and runtime behavior. Here are Firestore-specific detection strategies:

Code Pattern Analysis

// Detection pattern: identify stale reference usage
const detectUAF = (code) => {
  const uafPatterns = [
    /get\(\)\s*\.delete\(\)\s*[^;]*\.data\(\)/g, // Get then delete then use
    /onSnapshot\(.*\)\s*\.docChanges\(\)\s*\[\^\]\s*\.data\(\)/g, // Snapshot iteration
    /runTransaction\(.*\)\s*get\(\)\s*delete\(\)\s*update\(\)/g // Transaction pattern
  ];
  
  return uafPatterns.some(pattern => pattern.test(code));
};

Runtime Monitoring

Firestore's security rules can help detect UAF-like conditions by validating document existence before operations:

// Security rules to catch UAF patterns
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write: if 
        // Check if document exists before allowing operations
        exists(/databases/$(database)/documents/users/$(userId)) &&
        // Additional validation logic
        request.auth != null;
    }
  }
}

Automated Scanning with middleBrick

middleBrick's Firestore-specific security scanning includes UAF detection through:

Check Type Detection Method Firestore Specificity
Reference Validation Analyzes code for stale document references Firestore SDK patterns
Transaction Analysis Examines transaction isolation boundaries Firestore transaction semantics
Real-time Listener Safety Validates snapshot iteration patterns Firestore onSnapshot behavior

The middleBrick CLI can scan your Firestore API endpoints for UAF vulnerabilities:

npm install -g middlebrick
middlebrick scan https://firestore.googleapis.com/ --api=firestore

middleBrick analyzes your Firestore API surface, identifying endpoints susceptible to UAF attacks and providing specific remediation guidance based on Firestore's unique architecture.

Firestore-Specific Remediation

Remediating Use After Free in Firestore requires Firestore-specific patterns and best practices. Here are effective solutions:

Existence Validation Pattern

// Safe pattern: validate existence before use
const safeGetAndProcess = async (docRef) => {
  const doc = await docRef.get();
  
  if (!doc.exists) {
    throw new Error('Document does not exist');
  }
  
  // Process only if document exists
  return processDocumentData(doc.data());
};

// Usage
const userRef = db.collection('users').doc(userId);
try {
  const userData = await safeGetAndProcess(userRef);
  // Safe to use userData
} catch (error) {
  // Handle missing document
  console.error('Document not found or deleted:', error);
}

Transaction-Based Safety

Use Firestore transactions to ensure atomicity and prevent UAF conditions:

// Transaction pattern for safe operations
const safeTransactionOperation = async (docRef, quantity) => {
  return await db.runTransaction(async (t) => {
    const doc = await t.get(docRef);
    
    if (!doc.exists) {
      throw new Error('Document deleted during transaction');
    }
    
    const currentData = doc.data();
    const newStock = currentData.stock - quantity;
    
    if (newStock < 0) {
      throw new Error('Insufficient stock');
    }
    
    t.update(docRef, { stock: newStock });
    return { success: true, newStock };
  });
};

Listener Cleanup Pattern

Properly manage real-time listeners to prevent UAF in snapshot processing:

// Safe listener pattern
const setupSafeListener = (docRef, callback) => {
  return docRef.onSnapshot({
    includeMetadataChanges: true,
    next: (snapshot) => {
      if (!snapshot.exists) {
        callback(null, 'deleted');
        return;
      }
      
      callback(snapshot.data(), 'exists');
    },
    error: (error) => {
      console.error('Listener error:', error);
    }
  });
};

// Usage
const userRef = db.collection('users').doc(userId);
const unsubscribe = setupSafeListener(userRef, (data, status) => {
  if (status === 'deleted') {
    console.log('User document was deleted');
    unsubscribe(); // Clean up listener
  } else {
    console.log('User data:', data);
  }
});

middleBrick Remediation Guidance

When middleBrick detects UAF vulnerabilities in your Firestore implementation, it provides specific remediation guidance:

middlebrick scan results:
✅ Firestore API Scanned
⚠️  Use After Free Risk Detected

Vulnerability: Stale document reference in transaction
Location: src/orders/service.js:42-48
Severity: Medium
Remediation: 
1. Add existence check before document operations
2. Use Firestore transactions for atomic operations
3. Implement proper error handling for deleted documents

middleBrick CLI provides these specific recommendations based on your actual code patterns, helping you fix UAF vulnerabilities efficiently.

Frequently Asked Questions

How does Use After Free differ in Firestore compared to traditional databases?

Firestore's real-time capabilities and eventual consistency model create unique UAF scenarios. Unlike traditional databases where transactions are ACID-compliant by default, Firestore's distributed nature means document states can change between operations. The onSnapshot listeners add another dimension where documents can be deleted during iteration, creating race conditions that don't exist in traditional SQL databases.

Can middleBrick detect Use After Free in Firestore security rules?

Yes, middleBrick analyzes Firestore security rules for UAF-related patterns. It checks for rules that might allow operations on documents without validating their existence, and identifies patterns where rule logic assumes document state remains constant. The scanner also examines rule complexity that could lead to timing attacks exploiting UAF conditions.