HIGH identification failuresfeathersjsmongodb

Identification Failures in Feathersjs with Mongodb

Identification Failures in Feathersjs with Mongodb — how this combination creates or exposes the vulnerability

Identification failures occur when an API fails to properly ensure that a subject (for example, a user or service) is who or what it claims to be, or when it incorrectly applies identity-based authorization decisions. In a Feathersjs service backed by MongoDB, this typically manifests as Insecure Direct Object References (IDOR) or Broken Object Level Authorization (BOLA), where access controls are evaluated using identifiers that can be tampered with (e.g., :id in route parameters) without verifying that the authenticated subject owns or is allowed to access the targeted document.

Feathersjs abstracts services via hooks and models, which can inadvertently encourage unsafe patterns. When using the MongoDB adapter, developers may bind incoming identifiers directly to queries without confirming that the authenticated entity has permission to access that specific record. For example, a GET /messages/:id endpoint might resolve the :id against MongoDB without cross-checking the user ID stored in the JWT or session. Because MongoDB does not enforce application-level ownership by default, the database will return the document if the _id matches, regardless of whether the requester should see it. This mismatch between service-layer identity and database-level permissions creates an identification failure.

Another common vector involves query filters that incorporate user-controlled input without scoping to the authenticated subject. If a service method accepts a query such as { user_id: req.user.id } but also allows overriding or merging partial user input, an attacker can supply a different user_id in the payload and retrieve records belonging to other users. The Feathersjs hooks lifecycle can exacerbate this if custom code injects parameters late in the chain or if multiple hooks modify the same query object. Additionally, default adapters often return raw MongoDB documents including _id, and if the client-side framework uses those IDs to construct navigation or API calls, it may encourage clients to iterate through identifiers, increasing exposure.

Real-world attack patterns include changing numeric or ObjectId values in URLs, manipulating JSON payloads, or leveraging tools like Burp Suite to replay modified requests. These techniques map to OWASP API Top 10 A01:2023 (Broken Object Level Authorization) and can lead to unauthorized access to sensitive records. In the context of compliance frameworks referenced by middleBrick findings, identification failures frequently contribute to violations under SOC2 and GDPR, where access must be limited to authorized subjects. The scanner’s BOLA/IDOR and Authentication checks are designed to detect these classes of issues by correlating runtime behavior with the OpenAPI spec and validating that identity scopes are enforced consistently.

Mongodb-Specific Remediation in Feathersjs — concrete code fixes

Remediation focuses on ensuring that every data access path enforces identity scoping and validates that the authenticated subject matches the document’s ownership. Below are concrete, syntactically correct examples for Feathersjs using the MongoDB adapter.

1. Scoped queries via hooks

Modify the before hook to append the authenticated user’s ID to the query. This ensures that even if a client sends an arbitrary :id, the database will only return documents belonging to that user.

const { iff, isProvider } = require('@feathersjs/authentication-hooks');

app.service('messages').hooks({
  before: {
    all: [
      iff(isProvider('external'), authenticate('jwt')),
      (context) => {
        if (context.params.user) {
          // Scope queries to the authenticated user
          if (typeof context.params.query.userId === 'undefined') {
            context.params.query.userId = context.params.user._id;
          } else if (context.params.query.userId !== String(context.params.user._id)) {
            // Reject attempts to query another user's data
            throw new Error('Forbidden: user_id mismatch');
          }
        }
        return context;
      }
    ]
  }
});

2. Strict _id resolution in a custom get method

Override the get handler to verify ownership before returning a document. This prevents direct ID manipulation from exposing other users’ records.

const { authenticate } = require('@feathersjs/authentication');

app.service('messages').hooks({
  before: {
    get: [
      authenticate('jwt'),
      async (context) => {
        const message = await context.app.service('messages').Model.findOne({
          _id: context.id,
          userId: context.params.user._id
        }).exec();
        if (!message) {
          throw new Error('Not found or access denied');
        }
        // Replace the id with the full document for downstream handlers
        context.result = message;
        return context;
      }
    ]
  }
});

3. Avoid merging untrusted input into query filters

When using find, explicitly set userId and avoid spreading raw query parameters that an attacker could modify.

app.service('messages').hooks({
  before: {
    find: [
      authenticate('jwt'),
      (context) => {
        // Explicitly set scoping; do not trust context.query.userId from client
        context.params.query = {
          userId: context.params.user._id,
          $limit: 50
        };
        return context;
      }
    ]
  }
});

4. Validate ObjectIds and reject malformed identifiers

Use a hook to ensure that :id parameters are valid MongoDB ObjectIds before they reach the adapter, reducing injection or confusion attacks.

const { ObjectId } = require('mongodb');

app.hooks({
  before: {
    all: [
      (context) => {
        if (context.id && typeof context.id === 'string') {
          if (!ObjectId.isValid(context.id)) {
            throw new Error('Invalid identifier');
          }
          // Optionally convert to ObjectId for strict matching
          context.id = new ObjectId(context.id);
        }
        return context;
      }
    ]
  }
});

5. Enforce ownership checks in after hooks for auditing

Log or raise alerts when a request attempts to access a resource outside the user’s scope, which helps detect probing or automated attacks.

app.service('messages').hooks({
  after: {
    all: [
      (context) => {
        if (context.result && Array.isArray(context.result.data)) {
          context.result.data.forEach((doc) => {
            if (String(doc.userId) !== String(context.params.user._id)) {
              // This should not happen due to scoped queries; if it does, alert
              console.warn('Potential IDOR detected:', context.path, doc._id);
            }
          });
        }
        return context;
      }
    ]
  }
});

These patterns align with the middleware and hook model that Feathersjs encourages, and they integrate naturally with the MongoDB adapter’s promise-based API. When combined with the Authentication, BOLA/IDOR, and Property Authorization checks provided by middleBrick’s scans, they reduce the likelihood of identification failures. Note that middleBrick detects and reports these classes of issues; it does not apply fixes automatically.

Frequently Asked Questions

How can I verify that my Feathersjs service properly scopes MongoDB queries to the authenticated user?
Use a tool like middleBrick to run the BOLA/IDOR and Authentication checks against your live endpoint. Additionally, write unit or integration tests that simulate requests with modified identifiers and confirm that only documents with matching userId are returned.
Does enabling authentication in Feathersjs automatically prevent identification failures?
No. Authentication confirms identity, but you must still scope queries and validate that each endpoint enforces ownership. A missing scope in a hook can still lead to IDOR even when authentication is enabled.