HIGH bola idorhapijavascript

Bola Idor in Hapi (Javascript)

Bola Idor in Hapi with Javascript — how this specific combination creates or exposes the vulnerability

Broken Object Level Authorization (BOLA) occurs when an API fails to enforce authorization checks on object identifiers, allowing one user to access or modify another user’s resources. In Hapi, a Node.js framework, this commonly arises when routes use user-supplied IDs (e.g., userId, recordId) to directly look up resources in a database without validating that the requesting user owns or is permitted to access that object.

Consider a route that retrieves a user profile by ID:

// vulnerable-hapi-server.js
const Hapi = require('@hapi/hapi');

const init = async () => {
  const server = Hapi.server({ port: 4000 });

  // Simulated data layer
  const users = [
    { id: 1, username: 'alice', email: '[email protected]' },
    { id: 2, username: 'bob', email: '[email protected]' }
  ];

  server.route({
    method: 'GET',
    path: '/users/{id}',
    handler: (request, h) => {
      const id = Number(request.params.id);
      const user = users.find(u => u.id === id);
      if (!user) {
        return { error: 'Not found' };
      }
      // BOLA: no check that the requesting user is allowed to view this user
      return user;
    }
  });

  await server.start();
  console.log('Server running on %s', server.info.uri);
};

init();

In this example, any authenticated or even unauthenticated caller can enumerate user records by incrementing the ID, because the handler does not verify whether the requesting actor has permission to view the target user. An attacker can chain this with ID enumeration to map valid user IDs and exfiltrate private data, which maps to the OWASP API Top 10 API1:2023 – Broken Object Level Authorization category and can be surfaced by middleBrick’s BOLA/IDOR check during a scan.

Hapi’s request lifecycle includes pre‑handlers and auth strategies, but developers must explicitly implement ownership checks. For instance, if the API uses JWTs, the token payload typically contains a subject (sub) representing the current user ID. A BOLA flaw exists when the route handler ignores this subject and trusts the incoming parameter. Even when using an external data store (e.g., SQL or NoSQL), failing to scope queries by the authenticated user’s ID enables BOLA. middleBrick’s unauthenticated scan can detect such endpoints by probing IDs across users and observing whether data is returned, highlighting the need for runtime authorization that aligns with the spec definitions analyzed via OpenAPI/Swagger with full $ref resolution.

Additional risk patterns include indirect references (e.g., sequentially assigned keys) and mass assignment where an attacker can overwrite other users’ fields by supplying unexpected properties. Because Hapi routes often rely on plugins for validation (e.g., joi), developers might mistakenly assume validation alone prevents BOLA. Validation ensures data shape but does not replace authorization, and middleBrick’s checks are designed to catch these gaps by correlating spec definitions with observed behavior across the unauthenticated attack surface.

Javascript-Specific Remediation in Hapi — concrete code fixes

To remediate BOLA in Hapi with JavaScript, enforce ownership checks in route handlers and centralize authorization logic. Always bind the authenticated subject from the request’s auth credentials to the resource lookup, and scope database queries accordingly.

Here is a secure pattern for the previous example:

// secure-hapi-server.js
const Hapi = require('@hapi/hapi');

const init = async () => {
  const server = Hapi.server({ port: 4000 });

  // Simulated data layer with ownership check
  const users = [
    { id: 1, username: 'alice', email: '[email protected]' },
    { id: 2, username: 'bob', email: '[email protected]' }
  ];

  server.route({
    method: 'GET',
    path: '/users/{id}',
    options: {
      // Assume an auth strategy that sets request.auth.credentials.userId
      auth: 'jwt',
      handler: (request, h) => {
        const requestedId = Number(request.params.id);
        const currentUserId = request.auth.credentials.userId;

        // BOLA fix: ensure the requested ID matches the authenticated user
        if (requestedId !== currentUserId) {
          return { error: 'Forbidden' };
        }

        const user = users.find(u => u.id === requestedId);
        if (!user) {
          return { error: 'Not found' };
        }
        return user;
      }
    }
  });

  await server.start();
  console.log('Server running on %s', server.info.uri);
};

init();

In this secure version, the route requires JWT authentication and compares the userId from the token with the id path parameter. If they do not match, a 403 response is returned, effectively mitigating BOLA. For more complex relationships (e.g., a user managing a team), centralize the permission check in a service function:

// permissions.js
const canViewUser = (currentUserId, targetUserId) => {
  return currentUserId === targetUserId;
};

module.exports = { canViewUser };

// secure-hapi-server.js (continued)
const { canViewUser } = require('./permissions');

server.route({
  method: 'GET',
  path: '/users/{id}',
  options: {
    auth: 'jwt',
    handler: (request, h) => {
      const requestedId = Number(request.params.id);
      const currentUserId = request.auth.credentials.userId;

      if (!canViewUser(currentUserId, requestedId)) {
        return { error: 'Forbidden' };
      }

      const user = users.find(u => u.id === requestedId);
      return user || { error: 'Not found' };
    }
  }
});

When using a database, scope queries by the authenticated user ID instead of fetching by raw ID alone. For example, with a SQL client, replace SELECT * FROM users WHERE id = $1 with SELECT * FROM users WHERE id = $1 AND team_id IN (SELECT team_id FROM memberships WHERE user_id = $2), passing both the target ID and the current user ID. This pattern aligns with the checks performed during middleBrick’s scans and helps ensure findings from the dashboard or CLI (using middlebrick scan <url>) confirm proper authorization boundaries. In CI/CD, the GitHub Action can fail builds if a scan detects BOLA, and the MCP Server allows you to run checks directly from IDEs while developing JavaScript routes.

Additional best practices include avoiding direct exposure of internal IDs in URLs where possible, using opaque references for public-facing identifiers, and validating and sanitizing all inputs even when authorization is enforced. Remember that middleBrick detects and reports these issues but does not fix or block; developers must implement the described safeguards based on the remediation guidance provided in the scan report.

Related CWEs: bolaAuthorization

CWE IDNameSeverity
CWE-250Execution with Unnecessary Privileges HIGH
CWE-639Insecure Direct Object Reference CRITICAL
CWE-732Incorrect Permission Assignment HIGH

Frequently Asked Questions

Can BOLA happen even if an API uses JWTs for authentication?
Yes. BOLA is about authorization, not authentication. If a route uses JWTs to identify a user but does not verify that the authenticated user is allowed to access the requested resource (e.g., by comparing the token’s user ID with the ID in the URL), BOLA can still occur.
How does middleBrick detect BOLA in Hapi endpoints?
middleBrick runs unauthenticated scans that probe endpoints with different object IDs and checks whether data is returned across users. It correlates these runtime observations with OpenAPI/Swagger spec definitions (with full $ref resolution) to highlight missing authorization constraints that match BOLA/IDOR findings.