HIGH brute force attackhapimutual tls

Brute Force Attack in Hapi with Mutual Tls

Brute Force Attack in Hapi with Mutual Tls — how this specific combination creates or exposes the vulnerability

A brute force attack targets authentication by systematically trying many credentials or session tokens. Hapi, a Node.js framework, does not inherently prevent credential guessing, and when mutual TLS is used, the presence of client certificates can shift attacker focus to account enumeration or session token brute forcing over an authenticated TLS channel.

Mutual TLS (mTLS) ensures that both client and server present valid certificates during the TLS handshake. In Hapi, this is typically enforced by configuring the TLS layer to request and verify client certificates. While mTLS strongly binds identity to a cryptographic certificate, it does not automatically protect the application layer from brute force attempts once the TLS connection is established. For example, an endpoint that accepts a username and password can still be hammered with many combinations, and an attacker who has obtained a valid client certificate (through compromise or social engineering) can use it to bypass other authentication factors, making brute force focused on account enumeration or token exhaustion more effective.

The combination can expose subtle gaps: certificate-based authentication narrows the identity scope to holders of a valid certificate, but if the application does not enforce rate limiting, account lockout, or strong password policies, attackers can iterate over usernames or session identifiers within the trusted TLS context. Moreover, if Hapi routes do not uniformly require mTLS and some endpoints fall back to weaker authentication, attackers may pivot to those routes. The risk is not that mTLS weakens brute force, but that it changes the attack surface: successful certificate validation may give the attacker a foothold, after which application-layer brute force techniques (e.g., credential stuffing, token guessing, or session fixation) become the primary vector.

Consider an Hapi route that uses mTLS for client authentication but still relies on simple API keys passed in headers. An attacker with a valid certificate can brute force the API key space because the TLS layer already validated the client. Additionally, if the server does not differentiate between certificate validation errors and authentication failures, it may leak information that aids enumeration. The OWASP API Security Top 10 category ‘Broken Object Level Authorization’ (BOLA) intersects here: even with mTLS, improper authorization checks allow an authenticated client to probe other users’ resources via brute force token or ID manipulation.

Real-world patterns mirror this: an attacker with a stolen client certificate might target endpoints like /api/v1/users/{id} by incrementing numeric IDs, testing whether certificate-bound authentication is paired with proper ownership checks. Tools such as Burp Suite can be used to replay requests with mutated identifiers while the TLS session remains valid. Another scenario involves LLM/AI endpoints secured with mTLS where prompts or model parameters are iteratively probed for data leakage or cost exploitation, combining SSL client auth with prompt injection or token exhaustion techniques.

To detect such risks, scanners like middleBrick run parallel checks including Authentication, BOLA/IDOR, and Rate Limiting, comparing OpenAPI/Swagger specs (with full $ref resolution) against runtime behavior. For LLM-related endpoints, the scanner also tests for System prompt leakage and active prompt injection probes, ensuring that mTLS does not obscure application-layer weaknesses.

Mutual Tls-Specific Remediation in Hapi — concrete code fixes

Remediation centers on ensuring mTLS is consistently applied, strengthening authentication, and hardening endpoints against brute force. Below are concrete steps and Hapi code examples.

1. Enforce mTLS across all routes and validate client certificates properly:

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

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

  server.route({
    method: 'GET',
    path: '/api/secure',
    options: {
      tls: {
        // Require client certificate for this route
        certs: [fs.readFileSync('/etc/ssl/certs/client-ca.pem')]
      },
      handler: (request, h) => {
        const cert = request.socket.getPeerCertificate();
        return { message: 'OK', subject: cert.subject };
      }
    }
  });

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

init().catch(err => {
  console.error(err);
  process.exit(1);
});

2. Add application-level rate limiting and account lockout to mitigate brute force attempts even when mTLS is in place:

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

const limiter = new RateLimiter({
  bucketCount: 10,
  bucketLimit: 5,
  ttl: 60
});

server.ext('onPreHandler', async (request, h) => {
  const allowed = await limiter.removeToken(request.info.remoteAddress);
  if (!allowed) {
    return h.response({ error: 'Too many requests' }).code(429);
  }
  return h.continue;
});

3. Ensure consistent authentication requirements and avoid fallback to weaker schemes. If using API keys or tokens, validate them within the mTLS context and bind them to the certificate subject or SAN:

server.ext('onPostAuth', async (request, h) => {
  const cert = request.socket.getPeerCertificate();
  const allowedSubjects = ['CN=alice.example.com', 'CN=bob.example.com'];
  if (!cert.subject || !allowedSubjects.includes(cert.subject)) {
    return h.response({ error: 'Forbidden' }).code(403);
  }
  // Optionally map certificate to user roles
  request.auth.credentials = { user: mapSubjectToUser(cert.subject) };
  return h.continue;
});

4. Use strong cipher suites and prefer TLS 1.2+ to reduce the risk of downgrade attacks that could weaken mTLS:

const server = Hapi.server({
  port: 443,
  host: '0.0.0.0',
  tls: {
    key: fs.readFileSync('/etc/ssl/private/server-key.pem'),
    cert: fs.readFileSync('/etc/ssl/certs/server-cert.pem'),
    ca: fs.readFileSync('/etc/ssl/certs/ca-bundle.pem'),
    requestCert: true,
    rejectUnauthorized: true,
    ciphers: 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_ECDHE-RSA-AES256-GCM-SHA384',
    minVersion: 'TLSv1.2'
  }
});

5. Apply authorization checks on every route to prevent BOLA/IDOR, even when mTLS provides authentication. Validate that the requesting certificate maps to the resource being accessed:

server.route({
  method: 'GET',
  path: '/api/users/{id}',
  options: {
    handler: (request, h) => {
      const cert = request.socket.getPeerCertificate();
      const userId = request.params.id;
      if (!canAccessUserId(cert, userId)) {
        return h.response({ error: 'Unauthorized' }).code(403);
      }
      return fetchUser(userId);
    }
  }
});

By combining strict mTLS configuration with rate limiting, consistent authorization, and cipher hardening, you reduce the effectiveness of brute force attacks that rely on the TLS layer for identity.

Frequently Asked Questions

Does mutual TLS alone prevent brute force attacks in Hapi?
No. Mutual TLS binds client identity to a certificate but does not stop credential or token brute forcing at the application layer. You still need rate limiting, account lockout, and proper authorization.
How does middleBrick help detect brute force risks with mTLS?
middleBrick checks Authentication, BOLA/IDOR, and Rate Limiting while comparing OpenAPI/Swagger specs (with full $ref resolution) to runtime behavior, identifying gaps where mTLS does not protect against application-layer brute force.