HIGH broken access controlstrapifirestore

Broken Access Control in Strapi with Firestore

Broken Access Control in Strapi with Firestore — how this specific combination creates or exposes the vulnerability

Broken Access Control occurs when API endpoints fail to enforce proper authorization checks, allowing one user to access or modify another user’s resources. Strapi, a headless CMS, often exposes GraphQL or REST endpoints that directly map to data models. When the underlying database is Google Firestore, misconfigured security rules or overly permissive queries can cause authorization logic to be evaluated client-side or skipped entirely on the backend.

In Strapi with Firestore, content is typically stored in collections such as users or articles. If a controller action retrieves documents using a query like where: ['user_id', '==', userId] but does not validate that the requesting user matches userId before passing the query to Firestore, an authenticated but malicious user can manipulate parameters to access other users’ documents. Firestore security rules are intended to enforce this, yet Strapi’s service-layer logic may bypass rule enforcement by constructing queries with elevated privileges (e.g., using a service account or admin SDK initialization).

Furthermore, the combination of Strapi’s role-based access control (RBAC) and Firestore’s rule-based model can lead to inconsistencies. Strapi roles may permit an endpoint call, while Firestore rules remain silent on specific document-level constraints, or vice versa. This gap enables BOLA (Broken Level Authorization) / IDOR when endpoints expose document IDs directly in URLs without verifying ownership or scope. For example, a request to /articles/123 may return data if Strapi permissions allow it, even when Firestore rules for user 123 are not aligned with the authenticated identity. Attackers can exploit this by iterating over known IDs, leveraging predictable resource naming patterns.

Another vector involves field-level authorization. Strapi may return sensitive fields such as email or role in responses because the content API response is not filtered, even when Firestore rules restrict read access to certain attributes. This data exposure compounds Broken Access Control by revealing information that should remain private. Insecure default configurations in newly initialized projects or plugins can further weaken the boundary between authenticated contexts, making it critical to validate every data access path.

Firestore-Specific Remediation in Strapi — concrete code fixes

Remediation focuses on aligning Strapi service logic with Firestore security rules and ensuring every query is scoped to the authenticated user. Always retrieve the user identity from the request context and enforce ownership checks before constructing Firestore queries. Avoid relying solely on Strapi’s role-based permissions for document-level authorization.

Example: Securing a user-specific documents endpoint

// src/api/article/controllers/article.js
'use strict';

const { initializeApp } = require('firebase-admin/app');
const { getFirestore } = require('firebase-admin/firestore');

// Ensure admin SDK is initialized safely, e.g., via environment checks
if (!initializeApp.apps.length) {
  initializeApp();
}
const db = getFirestore();

async function findUserArticles(ctx) {
  const user = ctx.state.user; // authenticated user from Strapi context
  if (!user || !user.id) {
    ctx.throw(401, 'Unauthorized: missing user identity');
  }

  const userRef = db.collection('users').doc(user.id);
  const snapshot = await userRef.collection('articles')
    .where('published', '==', true)
    .orderBy('createdAt', 'desc')
    .limit(50)
    .get();

  const articles = [];
  snapshot.forEach(doc => {
    articles.push({ id: doc.id, ...doc.data() });
  });
  return articles;
}

module.exports = { findUserArticles };

This approach scopes documents to the authenticated user’s subcollection, ensuring Firestore rules can further validate access. The query is executed under the service account’s permissions, but because the document path includes the user ID, misconfigured broader rules are less likely to expose unrelated data.

Firestore security rule alignment example

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId}/articles/{articleId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
      allow list: if request.auth != null && request.auth.uid == userId;
    }
  }
}

With this rule, even if Strapi’s controller mistakenly uses a broader collection reference, Firestore will reject requests where request.auth.uid does not match the path’s userId. Strapi should still enforce its own checks to avoid unnecessary load and provide consistent error handling.

Remediation for list endpoints with pagination

async function listUserArticles(ctx) {
  const user = ctx.state.user;
  const { page = 1, pageSize = 20 } = ctx.query;
  const offset = (page - 1) * pageSize;

  const userRef = db.collection('users').doc(user.id);
  const snapshot = await userRef.collection('articles')
    .orderBy('createdAt', 'desc')
    .offset(offset)
    .limit(parseInt(pageSize, 10))
    .get();

  const articles = [];
  snapshot.forEach(doc => {
    articles.push({ id: doc.id, ...doc.data() });
  });

  ctx.body = { data: articles, page: parseInt(page, 10), pageSize: parseInt(pageSize, 10) };
}

By anchoring queries to the user’s document path and avoiding global collection scans, you reduce the risk of IDOR. Always validate pagination inputs and avoid exposing internal document IDs in URLs where possible; use opaque identifiers or mapping tables if necessary.

Frequently Asked Questions

How can I verify that Firestore rules are correctly enforced by Strapi?
Test endpoints with different authenticated contexts and inspect the constructed query paths. Ensure each request uses a user-specific scope (e.g., users/{uid}/articles) and that Firestore rules reject mismatched UIDs. Combine Strapi role checks with Firestore rule assertions for defense in depth.
Does using middleBrick help detect Broken Access Control in Strapi with Firestore?
middleBrick scans unauthenticated attack surfaces and includes checks for BOLA/IDOR and Property Authorization across OpenAPI specs and runtime behavior. It can surface misconfigurations in authorization logic and mapping between Strapi roles and Firestore rules, providing findings with severity and remediation guidance.