HIGH pii leakageexpressfirestore

Pii Leakage in Express with Firestore

Pii Leakage in Express with Firestore — how this specific combination creates or exposes the vulnerability

When an Express application uses Google Cloud Firestore as a backend, PII leakage commonly arises from insecure data modeling and overly permissive read paths. Firestore’s document and collection structure can inadvertently expose sensitive fields such as email, phone, or government identifiers if rules and application logic do not enforce least-privilege access.

In this stack, developers often map user profiles or session objects directly to Firestore documents. Without field-level filtering, an API endpoint that returns a full document may expose PII to unauthenticated or low-privilege callers. For example, an endpoint like /api/users/:userId that performs db.collection('users').doc(userId).get() and sends the entire snapshot back can leak data when the caller should only see a display name.

Another common pattern is using Firestore security rules that focus solely on document existence or ownership, but omit explicit field masks. Rules such as allow read: if request.auth != null; permit a fully authenticated user to read all fields, including PII that might be needed only by a privileged service. If the Express route does not sanitize the document server-side before sending the response, the API becomes a direct channel for PII leakage.

A third contributor is the use of Firestore queries that return multiple documents without projection. Queries like db.collection('profiles').where('public', '==', false).get() can return private fields when the query is allowed by rules but the Express handler streams the results unchanged to the client. Combined with weak authentication or misconfigured CORS, this enables enumeration or exfiltration of sensitive records.

middleBrick detects these risks through its unauthenticated, black-box scan, exercising endpoints and inspecting Firestore rules behavior where observable. It flags exposed PII by analyzing the API surface and cross-referencing findings with the OpenAPI spec, identifying inconsistencies between intended and actual data exposure. The scanner also checks for missing input validation on identifiers that could lead to horizontal privilege escalation across user documents.

Remediation involves both server-side filtering in Express and tightening Firestore rules. You should return only necessary fields, apply role-based field masking, and validate ownership using robust identifiers. middleBrick’s findings include prioritized guidance and references to compliance mappings such as OWASP API Top 10 and GDPR, helping you understand the severity and required changes without implying automatic fixes.

Firestore-Specific Remediation in Express — concrete code fixes

To prevent PII leakage, implement field selection and strict rule checks in your Express handlers. Below are concrete, working examples that demonstrate secure patterns when working with Firestore.

First, use projection to limit returned fields. This ensures only non-sensitive data is sent to the client:

const express = require('express');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();

const router = express.Router();

router.get('/api/users/:userId/profile', async (req, res) => {
  try {
    const userId = req.params.userId;
    const snapshot = await db.collection('users')
      .doc(userId)
      .get({ fields: ['displayName', 'avatarUrl'] });

    if (!snapshot.exists) {
      return res.status(404).json({ error: 'Not found' });
    }

    res.json(snapshot.data());
  } catch (err) {
    res.status(500).json({ error: 'Internal server error' });
  }
});

module.exports = router;

Second, enforce ownership and field-level checks in Firestore security rules. Combine resource-based conditions with explicit field access patterns:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read: if request.auth != null && request.auth.uid == userId
        && request.resource.data.keys().hasAll(['displayName', 'avatarUrl'])
        && request.resource.data.diff(resource.data).affectedKeys().hasNone(['ssn', 'nationalId']);
      allow write: if request.auth != null && request.auth.uid == userId
        && request.resource.data.keys().hasAll(['displayName', 'avatarUrl'])
        && request.resource.data.diff(resource.data).affectedKeys().hasOnly(['displayName', 'avatarUrl']);
    }
  }
}

Third, for queries that return lists, apply server-side filtering and avoid exposing sensitive documents to unauthorized roles:

router.get('/api/profiles', async (req, res) => {
  try {
    const snapshot = await db.collection('profiles')
      .where('public', '==', true)
      .select('handle', 'status')
      .get();

    const results = [];
    snapshot.forEach(doc => results.push({ id: doc.id, ...doc.data() }));
    res.json(results);
  } catch (err) {
    res.status(500).json({ error: 'Internal server error' });
  }
});

module.exports = router;

These examples illustrate how to align Express routes with secure Firestore usage: limit returned data, validate ownership, and constrain rule conditions. middleBrick can surface deviations from these patterns by scanning your endpoints and spec, highlighting where PII exposure is likely and providing remediation guidance tied to recognized frameworks.

Related CWEs: dataExposure

CWE IDNameSeverity
CWE-200Exposure of Sensitive Information HIGH
CWE-209Error Information Disclosure MEDIUM
CWE-213Exposure of Sensitive Information Due to Incompatible Policies HIGH
CWE-215Insertion of Sensitive Information Into Debugging Code MEDIUM
CWE-312Cleartext Storage of Sensitive Information HIGH
CWE-359Exposure of Private Personal Information (PII) HIGH
CWE-522Insufficiently Protected Credentials CRITICAL
CWE-532Insertion of Sensitive Information into Log File MEDIUM
CWE-538Insertion of Sensitive Information into Externally-Accessible File HIGH
CWE-540Inclusion of Sensitive Information in Source Code HIGH

Frequently Asked Questions

How does Firestore’s document structure increase the risk of PII leakage in Express APIs?
Firestore documents can contain nested fields and maps that bundle PII with public data. If an Express route returns an entire document without field projection or server-side filtering, the API may expose sensitive fields such as emails or identifiers. Insecure rules that allow broad read access amplify this risk by permitting unauthorized retrieval of full documents.
Can Firestore security rules alone prevent PII leakage, or should Express always filter fields?
Rules provide a baseline, but Express should still filter fields. Rules may allow read access to a document while unintentionally permitting exposure of sensitive fields if rules lack explicit field constraints. Applying projection in Express adds a defense-in-depth layer, ensuring only intended non-PII fields are returned regardless of rule configuration changes.