Memory Leak in Adonisjs with Mutual Tls
Memory Leak in Adonisjs with Mutual Tls — how this specific combination creates or exposes the vulnerability
A memory leak in AdonisJS when mutual TLS (mTLS) is enabled typically arises from the interaction between long-lived HTTPS server instances and how TLS sessions and request contexts are managed. mTLS requires both client and server to present certificates, which increases per-connection state. If AdonisJS or application code holds references to request or context objects beyond the request lifecycle—such as storing request-scoped data in global caches, attaching listeners to TLS sockets that are not cleaned up, or retaining streams in module-level arrays—these references can prevent garbage collection. Over time, repeated mTLS handshakes and persistent connections accumulate unreleased objects, leading to growing heap usage. This pattern is more pronounced under mTLS because each connection carries additional certificate metadata and session state compared to unencrypted or one-way TLS traffic.
Another contributing factor is improper handling of secure server options and streams within AdonisJS providers or custom server boots. For example, creating a new secure server instance per route or failing to reuse a properly configured HTTPS server can multiply TLS contexts and associated buffers. MiddleBrick scans can surface related findings such as Input Validation and Unsafe Consumption when malformed or unexpected certificates trigger abnormal code paths that exacerbate retention. While MiddleBrick does not fix or remediate, its findings include prioritized guidance to help developers address root causes like dangling references and unmanaged streams.
In practice, a leak may manifest as a steady increase in RSS and heap size under continuous mTLS traffic, with no immediate errors. Profiling tools can show many detached DOM-like structures or EventEmitter listeners that should have been released. Because mTLS adds cryptographic material and session tickets to each connection, the leak may accelerate compared to non-mTLS setups. Developers should correlate memory trends with the number of TLS handshakes and active secure connections, and use MiddleBrick’s unauthenticated scan to surface related configuration and validation issues that may contribute to retention.
Mutual Tls-Specific Remediation in Adonisjs — concrete code fixes
To mitigate memory leaks with mTLS in AdonisJS, focus on correct server creation, stream cleanup, and avoiding global retention of request-specific objects. Use a single reused HTTPS server instance with proper secure context options, and ensure all streams and listeners are released after each request.
Example: Proper mTLS server setup in AdonisJS
Configure the HTTPS server once in start/hooks.ts or a dedicated boot file, and reuse it across the application. This reduces the number of TLS contexts and avoids duplicated session state:
import { httpsServer } from '@adonisjs/core/types/server'
import fs from 'fs'
const tlsOptions = {
key: fs.readFileSync('/etc/ssl/private/server.key'),
cert: fs.readFileSync('/etc/ssl/certs/server.crt'),
ca: fs.readFileSync('/etc/ssl/certs/ca-bundle.crt'),
requestCert: true,
rejectUnauthorized: true,
}
export const server: httpsServer = {
async create() {
const https = await import('https')
const server = https.createServer(tlsOptions, (req, res) => {
// Handled by AdonisJS pipeline; keep this minimal
})
return server
},
}
Ensure that your server.ts references this shared server and does not create new instances per route or request:
import { defineServer } from '@adonisjs/core/server'
import { server as tlsServer } from './start/hooks'
export const server = defineServer({
hostname: '0.0.0.0',
port: 8443,
tls: tlsServer,
})
Avoid retaining request-scoped data globally
Do not attach large objects or streams to global variables or module-level arrays. Instead, use request-scoped storage (e.g., request.getPrivateStore()) and clean up in hooks or middleware:
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export const cleanupHook = {
async afterResponse(ctx: HttpContextContract) {
const store = ctx.getPrivateStore()
// Explicitly release references
store.dispose?.()
// Remove any temporary listeners
ctx.response.off('finish', someListener)
},
}
Profile heap usage while generating many mTLS handshakes to confirm that objects are being reclaimed. MiddleBrick can highlight related Input Validation and Data Exposure findings that may indicate problematic certificate handling paths, but remediation actions such as refactoring server lifecycle and scoping must be implemented by the development team.