HIGH ldap injectionfirestore

Ldap Injection in Firestore

How Ldap Injection Manifests in Firestore

Firestore injection vulnerabilities emerge when user-controlled input flows into query construction without proper sanitization. Unlike traditional LDAP injection targeting directory services, Firestore injection exploits the query language's parsing logic to manipulate database operations.

The most common pattern involves dynamic query building where user input becomes part of the query path or filter conditions. Consider a search endpoint that accepts user-provided collection names or field values:

// Vulnerable pattern - user input directly in collection path
const collectionName = req.query.collection || 'users';
const snapshot = await db.collection(collectionName).where('email', '==', req.query.email).get();

An attacker can manipulate the collection parameter to access unauthorized collections. More sophisticated attacks target query operators:

// Query operator injection vulnerability
const field = req.query.field || 'name';
const operator = req.query.operator || '==';
const value = req.query.value || 'John Doe';
const snapshot = await db.collection('users').where(field, operator, value).get();

Here, an attacker could set operator to > or < to bypass authorization checks, or craft field names that access nested properties they shouldn't see.

Firestore's document ID injection represents another attack vector. When document IDs are constructed from user input without validation:

// Document ID injection vulnerability
const userId = req.params.userId; // User-controlled
const docRef = db.collection('users').doc(userId);
const doc = await docRef.get();

An attacker might supply userId values like admin or serviceAccount to access privileged documents, especially if the application uses predictable ID patterns.

Array and map field injection also occurs when user input targets nested data structures:

// Array field injection
const fieldPath = req.query.field || 'roles.admin';
const snapshot = await db.collection('users').where(fieldPath, '==', true).get();

This could allow enumeration of administrative roles or other sensitive nested properties.

Firestore-Specific Detection

Detecting Firestore injection requires examining both code patterns and runtime behavior. Static analysis should flag these anti-patterns:

// Code patterns to flag
const vulnerablePatterns = [
  'db.collection(req.query',          // Dynamic collection names
  'where(req.query.field',           // Dynamic field names
  'where(req.query.operator',        // Dynamic operators
  'doc(req.query.id',                // Dynamic document IDs
  'orderBy(req.query.field',         // Dynamic ordering
  'limit(req.query.limit'            // Dynamic limits
];

Runtime detection focuses on query parameter validation. Implement strict whitelisting:

// Secure query construction with validation
const SAFE_FIELDS = ['name', 'email', 'createdAt'];
const SAFE_OPERATORS = ['==', '!=', '>', '<', '>=', '<='];

function validateQuery(field, operator, value) {
  if (!SAFE_FIELDS.includes(field)) {
    throw new Error('Invalid field');
  }
  if (!SAFE_OPERATORS.includes(operator)) {
    throw new Error('Invalid operator');
  }
  return true;
}

// Usage
const field = req.query.field;
const operator = req.query.operator;
const value = req.query.value;

validateQuery(field, operator, value);
const snapshot = await db.collection('users')
  .where(field, operator, value)
  .get();

Automated scanning with middleBrick identifies these vulnerabilities by analyzing your Firestore API endpoints. The scanner tests for:

  • Dynamic collection access attempts
  • Operator injection payloads
  • Document ID enumeration
  • Field path traversal
  • Array and map field manipulation

middleBrick's black-box scanning approach tests your unauthenticated API surface, attempting to manipulate query parameters to access unauthorized data. The scanner provides specific findings with severity ratings and remediation guidance tailored to Firestore's query language.

Firestore-Specific Remediation

Securing Firestore against injection requires architectural changes to how queries are constructed. The foundation is strict input validation and parameterized queries:

// Secure query builder pattern
class SecureQueryBuilder {
  constructor(collection) {
    this.collection = collection;
    this.query = db.collection(collection);
    this.allowedFields = new Set(['name', 'email', 'age', 'status']);
    this.allowedOperators = new Set(['==', '!=', '>', '<', '>=', '<=']);
  }

  where(field, operator, value) {
    if (!this.allowedFields.has(field)) {
      throw new Error(`Field ${field} not allowed`);
    }
    if (!this.allowedOperators.has(operator)) {
      throw new Error(`Operator ${operator} not allowed`);
    }
    this.query = this.query.where(field, operator, value);
    return this;
  }

  build() {
    return this.query;
  }
}

// Usage
const builder = new SecureQueryBuilder('users');
const query = builder
  .where('email', '==', req.query.email)
  .where('status', '==', 'active')
  .build();
const snapshot = await query.get();

For document access, implement ID validation and access control:

// Secure document access with validation
function getDocumentSafely(collection, docId, userId) {
  // Validate document ID format
  if (!/^[a-zA-Z0-9_-]{1,100}$/.test(docId)) {
    throw new Error('Invalid document ID format');
  }
  
  // Check authorization
  if (!await hasAccess(userId, collection, docId)) {
    throw new Error('Access denied');
  }
  
  return db.collection(collection).doc(docId).get();
}

// Usage
const doc = await getDocumentSafely('users', req.params.id, req.user.id);

Implement Firestore security rules to provide defense-in-depth:

{
  "rules": {
    "users": {
      "$userId": {
        ".read": "request.auth != null && request.auth.uid == $userId",
        ".write": "request.auth != null && request.auth.uid == $userId"
      }
    },
    "publicData": {
      ".read": "request.auth != null",
      ".write": "false"
    }
  }
}

Consider using Firebase Admin SDK's built-in validation features:

// Using Admin SDK validation
const admin = require('firebase-admin');
const db = admin.firestore();

// Validate document references
function validateDocumentRef(ref) {
  if (!(ref instanceof admin.firestore.DocumentReference)) {
    throw new Error('Invalid document reference');
  }
  return ref;
}

// Usage
const docRef = validateDocumentRef(db.collection('users').doc(req.params.id));

For complex queries, use stored procedures or predefined query templates rather than dynamic construction:

// Predefined query templates
const QUERY_TEMPLATES = {
  'findUserByEmail': (email) => db.collection('users')
    .where('email', '==', email)
    .where('active', '==', true)
    .limit(1),
  
  'findUsersByStatus': (status) => db.collection('users')
    .where('status', '==', status)
    .orderBy('createdAt', 'desc')
};

// Usage
const template = QUERY_TEMPLATES[req.query.template];
if (!template) {
  throw new Error('Invalid query template');
}
const snapshot = await template(req.query.param).get();

Frequently Asked Questions

How does Firestore injection differ from traditional SQL injection?
Firestore injection targets the NoSQL query language rather than SQL syntax. Instead of manipulating SQL statements, attackers manipulate collection names, field paths, operators, and document IDs. The attack surface includes dynamic query construction, improper input validation, and inadequate access controls. While SQL injection often involves UNION attacks and subqueries, Firestore injection focuses on unauthorized data access through query manipulation and document ID enumeration.
Can middleBrick detect Firestore injection vulnerabilities in my API?
Yes, middleBrick's black-box scanning tests your Firestore API endpoints for injection vulnerabilities by attempting to manipulate query parameters. The scanner tests dynamic collection access, operator injection, document ID enumeration, and field path traversal. It provides specific findings with severity ratings and remediation guidance. The free tier includes 3 scans per month, making it easy to test your APIs before production deployment.