HIGH broken access controlhapimutual tls

Broken Access Control in Hapi with Mutual Tls

Broken Access Control in Hapi with Mutual Tls — how this specific combination creates or exposes the vulnerability

Broken Access Control occurs when an API fails to enforce proper authorization between subjects, allowing one user to access or modify resources belonging to another. In Hapi, this commonly maps to the BOLA/IDOR checks in middleBrick’s 12 security categories. When Mutual Transport Layer Security (Mutual TLS) is used, the server authenticates the client via a client certificate, but it does not automatically enforce fine-grained access controls on top of that authentication. A common misconfiguration is to treat successful mTLS authentication as sufficient for authorization, assuming the certificate uniquely identifies a user or role. In practice, certificates may be issued per service, per environment, or shared across low-privilege service accounts. If the Hapi route handlers then use the certificate subject or serial number as a coarse identity for data scoping, an attacker who possesses any valid certificate can potentially traverse IDs in URL parameters or headers and access other users’ resources.

Consider an endpoint like GET /users/{id}. With mTLS enabled, Hapi may populate request.auth.credentials with certificate metadata (subject, issuer, serial). If the route does not additionally verify that the authenticated principal is allowed to view the specific {id}, a BOLA flaw exists. middleBrick’s BOLA/IDOR checks will flag this by correlating unauthenticated or low-privilege certificate access with ID manipulation in requests. Even when mTLS provides strong transport identity, missing property-level authorization allows horizontal privilege escalation. For example, an attacker could iterate numeric user IDs or UUID paths to enumerate profiles, invoices, or personal health information. This becomes more likely when certificate issuance policies do not map cleanly to application roles or tenant boundaries.

Input Validation issues often compound Broken Access Control in this setup. If route parameters or headers are not strictly validated, an attacker may inject malicious patterns (e.g., path traversal sequences or encoded null bytes) to bypass logical access checks that rely on string matching. In Hapi, failing to validate and sanitize request.params.id or related query fields can allow bypassing expected filters. middleBrick’s Input Validation checks highlight unsafe patterns such as missing allowlists, overly permissive regexes, or missing schema validation on payloads. When combined with weak authorization logic, malformed input can trick server-side logic into loading the wrong resource or escalating privileges.

Additionally, Rate Limiting misconfigurations can amplify the impact. Without per-identity or per-client throttling, an attacker with a valid certificate can probe IDs or perform mass enumeration without being throttled. middleBrick’s Rate Limiting checks examine whether controls exist at the scope required to mitigate abuse. Even with mTLS, if endpoints do not enforce request budgets tied to the certificate identity or tenant, attackers can conduct low-and-slow scans that evade simple IP-based limits.

Finally, Data Exposure and Encryption checks in middleBrick verify whether sensitive data is unnecessarily returned or transmitted. In a misconfigured Hapi service with mTLS, responses might include full user records when a subset is warranted, or error messages may leak internal identifiers. These findings reinforce the need to align authentication (mTLS), authorization (scoping by subject/tenant), and output hygiene to prevent Broken Access Control across the stack.

Mutual Tls-Specific Remediation in Hapi — concrete code fixes

To remediate Broken Access Control while retaining Mutual TLS, Hapi applications should enforce explicit authorization checks and strict input validation on every route, regardless of mTLS status. Below are concrete, working examples that demonstrate a secure pattern.

1. Configure mTLS in Hapi with explicit client certificate parsing

Use the TLS options to require client certificates and extract subject fields safely. Do not rely on certificate presence alone for authorization decisions.

const Hapi = require('@hapi/hapi');

const init = async () => {
  const server = Hapi.server({
    port: 443,
    tls: {
      key: require('fs').readFileSync('/etc/ssl/private/server.key'),
      cert: require('fs').readFileSync('/etc/ssl/certs/server.crt'),
      ca: require('fs').readFileSync('/etc/ssl/certs/ca-bundle.crt'),
      requestCert: true,
      rejectUnauthorized: true,
    },
  });

  server.ext('onPostAuth', (request, h) => {
    const credentials = request.auth.credentials;
    // credentials contains parsed client certificate fields when provided
    if (!credentials || !cetails.subject) {
      throw Boom.unauthorized('Client certificate required');
    }
    // Map certificate subject or serial to application identity
    request.auth.identity = {
      subject: credentials.subject,
      serial: credentials.serialNumber,
    };
    return h.continue;
  });

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

init().catch(console.error);

2. Enforce per-request authorization with scope checks

Add route-level handlers that validate ownership or tenant scope before returning data. Never trust certificate-derived identity alone.

server.route({
  method: 'GET',
  path: '/users/{id}',
  options: {
    validate: {
      params: {
        id: Joi.string().guid(), // strict validation
      },
    },
    handler: async (request, h) => {
      const requestingIdentity = request.auth.identity;
      const targetId = request.params.id;

      // Example: enforce tenant or user ownership
      const userRecord = await db.users.findByPk(targetId);
      if (!userRecord) {
        throw Boom.notFound('User not found');
      }

      // BOLA prevention: ensure the authenticated subject can access this resource
      if (userRecord.tenantId !== requestingIdentity.tenantId) {
        throw Boom.forbidden('Access denied to this resource');
      }

      // Return only necessary fields to limit data exposure
      return {
        id: userRecord.id,
        email: userRecord.email,
        profile: userRecord.profile,
      };
    },
  },
});

3. Apply input validation and canonicalization

Use Joi or similar schemas to sanitize and validate all inputs, preventing path traversal or injection that could bypass logical access checks.

const Joi = require('joi');

server.route({
  method: 'GET',
  path: '/documents/{documentId}',
  options: {
    validate: {
      params: {
        documentId: Joi.string().hex().length(24).required(),
      },
      query: Joi.object({
        version: Joi.number().integer().min(0).optional(),
      }),
    },
    handler: async (request, h) => {
      // handler logic with validated params
    },
  },
});

4. Scope rate limiting to identity or tenant

Use request headers or certificate-derived identifiers to apply per-client limits, reducing enumeration risk.

const rateLimit = require('@hapi/rate-limiter');

server.register(rateLimit, (err) => {
  if (err) {
    throw err;
  }

  server.ext('onPreResponse', (request, h) => {
    // Apply rate limits based on tenant or certificate serial
    const key = request.auth.identity.serial || request.auth.identity.subject;
    return rateLimit.limit({ key, limit: 100, window: '1m' });
  });
});

5. Minimize data exposure in responses

Ensure responses do not leak identifiers or sensitive fields that could aid enumeration. Combine with strict schema-based outputs.

server.route({
  method: 'GET',
  path: '/me',
  options: {
    auth: {
      mode: 'required',
      strategy: 'mTLS',
    },
    handler: (request, h) => {
      const identity = request.auth.identity;
      // Return only safe, needed fields
      return {
        subject: identity.subject,
        tenantId: identity.tenantId,
        capabilities: ['read:own_data'],
      };
    },
  },
});

These steps ensure that mTLS provides strong client authentication while explicit authorization, validation, rate limiting, and output controls prevent Broken Access Control. Regular scans with middleBrick can help detect deviations such as missing scope checks or unsafe input handling in mTLS-enabled routes.

Frequently Asked Questions

Does mTLS alone prevent Broken Access Control in Hapi?
No. Mutual TLS provides strong client authentication but does not enforce fine-grained authorization. You must add explicit scope and ownership checks in route handlers to prevent BOLA/IDOR.
How can I test if my Hapi endpoints are vulnerable to IDOR despite mTLS?
Use a client with a valid certificate to request other users' resources by manipulating identifiers in the URL. middleBrick’s BOLA/IDOR checks correlate mTLS authentication with ID manipulation to surface these flaws.