HIGH broken access controlexpressmongodb

Broken Access Control in Express with Mongodb

Broken Access Control in Express with Mongodb — how this specific combination creates or exposes the vulnerability

Broken Access Control in an Express + Mongodb stack typically occurs when authorization checks are missing or inconsistent at the route level and are not enforced by the database layer. Because Mongodb stores documents as rich structures, developers sometimes rely on application-side filters alone (e.g., matching req.user.id to a resource owner ID) without constraining queries with proper ownership or role predicates. This creates BOLA/IDOR conditions where an authenticated user can modify or retrieve another user’s data by changing an identifier in the request (e.g., /users/:id/profile).

Express itself does not enforce data permissions; it provides routing and middleware. If route handlers directly use user-supplied parameters (like req.params.id or query filters) to build Mongodb queries without validating that the requesting user has the right to access that document, the API surface is vulnerable. For example, a GET /api/users/:id handler that does db.collection('users').findOne({ _id: new ObjectId(req.params.id) }) without confirming the requester owns that _id exposes a BOLA flaw. Compounding this, permissive CORS or missing scoped middleware can allow broader unintended access across origins or services.

Additionally, if queries rely on client-supplied filters (e.g., { role: req.query.role }) without server-side role validation, privilege escalation becomes feasible. A regular user could inject isAdmin=true if the application does not sanitize and enforce role checks against the authenticated subject. Because Mongodb can return many fields by default, sensitive properties may be unintentionally exposed if field-level projection is not applied. These patterns align with the OWASP API Top 10 category for Broken Object Level Authorization and commonly appear in implementations that skip centralized authorization logic and strict query scoping.

middleBrick scans such endpoints using its BOLA/IDOR checks combined with Property Authorization and Input Validation tests, validating that object-level permissions are enforced and that untrusted input cannot alter query semantics. Findings include insecure direct object references, missing ownership predicates, and over-permissive query filters, each mapped to remediation guidance and compliance mappings like OWASP API Top 10 and SOC2 controls.

Mongodb-Specific Remediation in Express — concrete code fixes

To secure Express routes that use Mongodb, always enforce ownership and role checks in the query itself and avoid trusting client-supplied identifiers for access decisions. Use middleware to resolve the authenticated subject (e.g., from a session or JWT) and ensure every database operation includes that subject as a required filter component.

Example: Safe user profile endpoint with ownership check

const { MongoClient, ObjectId } = require('mongodb');
const express = require('express');
const app = express();

const client = new MongoClient('mongodb://localhost:27017');

async function getUserProfile(req, res) {
  const userId = req.user.sub; // authenticated subject from middleware, e.g., JWT payload
  const targetId = req.params.id;

  if (!ObjectId.isValid(targetId)) {
    return res.status(400).json({ error: 'Invalid user id' });
  }

  const database = client.db('appdb');
  const user = await database.collection('users').findOne({
    _id: new ObjectId(targetId),
    // Ownership enforced: only return docs where the document owner matches the authenticated user
    ownerId: userId
  }, {
    // Explicitly limit returned fields to avoid sensitive data exposure
    projection: { email: 1, profile: 1, _id: 1 }
  });

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

app.get('/api/users/:id', (req, res) => {
  getUserProfile(req, res).catch(() => res.status(500).json({ error: 'Internal error' }));
});

Example: Role-based access with server-side enforcement

async function updateSettings(req, res) {
  const userId = req.user.sub;
  const targetId = req.params.id;
  const { preferenceKey, preferenceValue } = req.body;

  if (!ObjectId.isValid(targetId)) {
    return res.status(400).json({ error: 'Invalid id' });
  }

  const database = client.db('appdb');
  // Ensure the requester is an admin or is updating their own settings
  const user = await database.collection('users').findOne({
    _id: new ObjectId(targetId),
    $or: [
      { role: 'admin' },
      { _id: new ObjectId(userId) }
    ]
  });

  if (!user) {
    return res.status(403).json({ error: 'Forbidden' });
  }

  const result = await database.collection('settings').updateOne(
    { userId: userId, key: preferenceKey },
    { $set: { value: preferenceValue, updatedAt: new Date() } },
    { upsert: true }
  );

  res.json({ modifiedCount: result.modifiedCount, upsertedId: result.upsertedId });
}

General practices

  • Always resolve the authenticated identity server-side (e.g., from a verified JWT or session) and include it in every query predicate.
  • Use ObjectId.isValid on user-supplied IDs before using them in queries to avoid injection or malformed document lookups.
  • Apply field projection to limit returned data and reduce exposure of sensitive attributes.
  • Do not pass raw user input directly as query keys or values; validate and transform input before using it in database operations.
  • Prefer parameterized updates and upserts with explicit ownership filters rather than client-supplied filter objects that can be manipulated.
  • Consider a centralized authorization layer or policy library to keep checks consistent across routes.

middleBrick’s CLI can be used to verify these fixes by scanning endpoints after changes: middlebrick scan https://api.example.com. The GitHub Action can enforce a minimum score in CI, and the MCP Server allows scanning from within AI coding assistants to catch regressions early.

Frequently Asked Questions

Why does including req.params.id directly in a Mongodb query create a BOLA risk?
Because it allows an authenticated user to manipulate the identifier to access another user’s document if ownership is not validated in the query. Always include the authenticated subject in the filter and validate identifiers before use.
How can projection help mitigate data exposure in Express + Mongodb APIs?
Projection limits the fields returned by Mongodb, reducing the chance that sensitive data is inadvertently exposed. Use explicit projection to return only necessary fields and avoid default broad returns.