Denial Of Service in Adonisjs with Mutual Tls
Denial Of Service in Adonisjs with Mutual Tls — how this specific combination creates or exposes the vulnerability
AdonisJS, a Node.js web framework, relies on the underlying Node.js TLS layer when configured for Mutual TLS (mTLS). mTLS requires both the client and server to present valid certificates during the TLS handshake. While mTLS strengthens authentication, the handshake and subsequent request parsing add computational overhead. In AdonisJS, this overhead is realized in the server’s TLS termination point and in the per-request certificate verification logic. An attacker can exploit this by establishing many concurrent TLS connections, each with a valid but unique client certificate, or by sending handshakes with intentionally large or malformed certificates. Each connection consumes event loop and memory resources for the TLS session and AdonisJS request lifecycle. Because the framework processes these requests synchronously during the initial handshake and early request parsing, resource consumption occurs before route or middleware protections are applied. This shifts the attack surface earlier in the request lifecycle compared to unauthenticated endpoints. The result is resource exhaustion—file descriptors, memory, or worker threads—leading to connection timeouts or process instability. Since mTLS endpoints are often used for sensitive internal services, the operational impact can be severe even when the API itself remains logically intact.
Compounding this, AdonisJS applications that use rate limiting or connection throttling may not apply these controls early enough in the mTLS flow. If limits are enforced only after the TLS handshake and controller invocation, the handshake and initial parsing still consume resources. In scans using middleBrick’s SSL/TLS and Rate Limiting checks, endpoints with mTLS but without pre-handshake protections can show higher susceptibility to denial patterns under concurrent load. The framework’s reliance on third-party TLS providers means configuration choices—such as strict certificate verification and session caching—directly affect resilience. Without proper tuning, valid client certificates do not prevent resource-based abuse. middleBrick’s Authentication and Rate Limiting checks can surface these risks by detecting missing pre-handling throttling and verifying that controls apply before expensive operations.
Mutual Tls-Specific Remediation in Adonisjs — concrete code fixes
To reduce Denial of Service risk in AdonisJS with mTLS, apply controls as close to the edge as possible and avoid expensive processing for unauthenticated or abusive connections. Use a reverse proxy or load balancer to terminate TLS and enforce connection limits before requests reach the Node.js process. Configure the proxy to validate client certificates and drop connections that exceed negotiated thresholds. Within AdonisJS, ensure that security-sensitive middleware such as rate limiting runs as early as possible, ideally in the request lifecycle before route matching or controller work. Combine this with robust TLS settings and resource boundaries.
Example: AdonisJS server with mTLS (server-side certificate verification)
const { Ignitor } = require('@adonisjs/ignitor')
const fs = require('fs')
Ignitor
.loadApp()
.httpServer()
.start()
.then(server => {
const tlsOptions = {
key: fs.readFileSync('path/to/server.key'),
cert: fs.readFileSync('path/to/server.crt'),
ca: [fs.readFileSync('path/to/ca.crt')],
requestCert: true,
rejectUnauthorized: true,
minVersion: 'TLSv1.2',
ciphers: 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256',
honorCipherOrder: true,
sessionTimeout: 300,
maxConnections: 500,
}
server.listener = server.listener.tls(tlsOptions)
console.log('AdonisJS mTLS server listening on 443')
})
.catch(err => {
console.error('Failed to start TLS server:', err)
process.exit(1)
})
Example: Enforce rate limiting before expensive middleware
Apply rate limiting in the global middleware stack early, using a token bucket approach with a shared store to prevent per-instance bypass. This reduces the chance of resource exhaustion from many TLS handshakes.
// start/kernel.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { middleware } from '@adonisjs/core'
class RateLimiter {
public async handle(ctx: HttpContextContract, next: () => Promise<void>) {
const ip = ctx.request.ip()
const allowed = await this.allowRequest(ip)
if (!allowed) {
ctx.response.status(429).send({ error: 'Too Many Requests' })
return
}
await next()
}
private async allowRequest(ip: string): Promise<boolean> {
// Implement a Redis or in-memory sliding window per IP
// Keep this check before route/controller work
return true // placeholder
}
}
export const http = middleware(RateLimiter)
Operational and configuration guidance
- Set reasonable maxConnections and timeouts in the TLS options to bound resources per node.
- Use session caching (sessionTimeout) to reduce full handshake overhead for repeat clients, but size the cache to avoid memory pressure.
- Deploy a WAF or reverse proxy in front of AdonisJS to filter malformed handshakes and enforce global rate limits before connections reach Node.js.
- Monitor file descriptors and event loop lag; mTLS with high concurrency can increase handle pressure.
- Leverage middleBrick’s Continuous Monitoring (Pro plan) to track TLS handshake durations and error rates; use CI/CD integration (GitHub Action) to fail builds if risk scores for SSL/TLS or Rate Limiting exceed your threshold.
Related CWEs: resourceConsumption
| CWE ID | Name | Severity |
|---|---|---|
| CWE-400 | Uncontrolled Resource Consumption | HIGH |
| CWE-770 | Allocation of Resources Without Limits | MEDIUM |
| CWE-799 | Improper Control of Interaction Frequency | MEDIUM |
| CWE-835 | Infinite Loop | HIGH |
| CWE-1050 | Excessive Platform Resource Consumption | MEDIUM |