Api Rate Abuse in Hapi with Mutual Tls
Api Rate Abuse in Hapi with Mutual Tls — how this specific combination creates or exposes the vulnerability
Rate abuse in Hapi when mutual TLS (mTLS) is used centers on the interaction between client certificate validation and request throttling. mTLS authenticates clients at the TLS layer by requiring a trusted client certificate, but it does not inherently limit how frequently an authenticated client can call an endpoint. If rate limiting is applied after mTLS authentication, an attacker who possesses a valid certificate can still open many connections and consume server resources, bypassing protections that rely only on IP-based or API-key rate limits.
In a Hapi server, this situation can arise when rate-limiting logic is implemented inside request lifecycle hooks (e.g., onPreAuth or onPreHandler) and depends on identifiers extracted from the request. With mTLS, the client certificate provides identity (subject or issuer), but if the server does not explicitly enforce per-certificate rate limits, a single certificate can be reused to flood specific routes or expensive operations. Additionally, TLS session resumption and connection pooling may allow many rapid requests over a small number of TLS handshakes, making abusive patterns harder to detect if rate checks are not consistently applied per certificate.
Another angle is that mTLS does not prevent abuse within authenticated sessions. For example, an authorized client performing token-swap or long-polling patterns can still generate high request volumes that exhaust backend concurrency or downstream dependencies. Because Hapi routes often rely on plugins for authentication and validation, misconfigured ordering—such as validating credentials before applying rate limits—can leave endpoints effectively unthrottled for mTLS-authenticated requests.
Real-world attack patterns relevant to this setup include rapid enumeration of user-specific endpoints (e.g., /users/{id}) using a valid certificate to probe for IDOR, or hammering computationally heavy endpoints to cause denial of service. These map to findings in categories such as Authentication and Rate Limiting, where the presence of mTLS is noted but insufficient to prevent abuse without explicit per-identity throttling.
middleBrick detects such scenarios by scanning the unauthenticated attack surface and correlating findings across its 12 security checks. For Hapi APIs with mTLS, it highlights missing rate controls for authenticated identities, misconfigured plugin ordering, and lack of per-certificate throttling, providing prioritized findings with severity and remediation guidance.
Mutual Tls-Specific Remediation in Hapi — concrete code fixes
To mitigate rate abuse in Hapi with mutual TLS, enforce rate limits keyed by certificate identity and ensure throttling runs before business logic. Use the client certificate’s subject or a mapped attribute to scope limits, and apply limits at the route or server level with a shared store to prevent bypass via multiple connections.
Example Hapi server with mTLS and rate limiting using hapi-auth-cert and a custom rate-limit plugin:
const Hapi = require('@hapi/hapi');
const CertAuth = require('hapi-auth-cert');
// Simple in-memory rate store; use Redis in production
const requestCounts = new Map();
function rateLimit(key, limit, windowMs) {
const now = Date.now();
if (!requestCounts.has(key)) {
requestCounts.set(key, { count: 1, start: now });
return { allowed: true, key };
}
const record = requestCounts.get(key);
if (now - record.start > windowMs) {
requestCounts.set(key, { count: 1, start: now });
return { allowed: true, key };
}
if (record.count >= limit) {
return { allowed: false, key };
}
record.count += 1;
return { allowed: true, key };
}
const init = async () => {
const server = Hapi.server({
port: 443,
tls: {
cert: process.env.SERVER_CERT,
key: process.env.SERVER_KEY,
ca: process.env.CA_CERT,
requestCert: true,
rejectUnauthorized: true
}
});
await server.register(CertAuth);
server.auth.strategy('cert', 'cert');
server.auth.default('cert');
server.ext('onPreAuth', (request, h) => {
const credentials = request.auth.credentials;
if (credentials && credentials.subject) {
const key = `cert:${credentials.subject}`;
const { allowed } = rateLimit(key, 100, 60_000); // 100 req/min per cert
if (!allowed) {
return h.response({ message: 'Rate limit exceeded' }).code(429);
}
}
return h.continue;
});
server.route({
method: 'GET',
path: '/users/{id}',
options: {
auth: 'cert',
handler: (request, h) => {
return { id: request.params.id };
}
}
});
await server.start();
console.log('Server running on %s', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.error(err);
process.exit(1);
});
init();
This example ties rate limits to the certificate subject, ensuring that each mTLS client is limited independently. For production, replace the in-memory map with a shared store such as Redis and consider additional signals like the cipher suite or issuer to scope limits more tightly.
When using the middleBrick CLI to scan a Hapi endpoint with mTLS, you can supply client certificate and key files so the scanner tests authenticated surface areas: middlebrick scan https://api.example.com --mtls-cert client.crt --mtls-key client.key. The dashboard then shows per-endpoint findings tied to authenticated identity, helping you identify routes missing throttling despite mTLS presence.
Additional hardening steps include tightening certificate issuance policies, rotating keys, and monitoring for repeated 429 responses per certificate via logs. Remember that middleBrick detects and reports these risks but does not apply fixes; use its remediation guidance to adjust your Hapi configuration and CI/CD checks accordingly.