Dns Rebinding in Adonisjs with Mutual Tls
Dns Rebinding in Adonisjs with Mutual Tls — how this specific combination creates or exposes the vulnerability
DNS rebinding is a network-based attack where an attacker manipulates DNS responses to make a victim’s browser believe a remote host is reachable at an internal IP address. In AdonisJS applications that rely on Mutual TLS (mTLS) for client authentication, this can create a dangerous bypass scenario. mTLS requires the client to present a valid certificate during the TLS handshake; if the server’s access control assumes the client IP alone is sufficient for authorization, an internal IP resolved via rebinding may be trusted implicitly.
Consider an AdonisJS API that exposes an administrative endpoint, e.g., /api/admin/reset, and uses IP-based allowlists in combination with mTLS. The server validates the client certificate but also checks that the request originates from a trusted internal subnet (e.g., 10.0.0.0/8). An attacker can host a malicious page on a public site that triggers DNS rebinding to resolve internal-admin.example.com to 127.0.0.1 or another internal IP. When the victim’s browser makes requests with its mTLS client certificate, AdonisJS may see a valid cert + an internal IP and grant access, even though the request did not originate from a trusted network boundary.
The risk is amplified when AdonisJS applications are deployed behind reverse proxies or load balancers that terminate TLS. If the proxy forwards the request to the application with an X-Forwarded-For header that reflects the rebinded IP, and the application trusts that header for IP-based checks, the mTLS assurance is effectively bypassed. This is a classic trust boundary violation: mTLS ensures client identity, but does not inherently prevent IP spoofing within the trusted network perimeter.
In practice, scanning an AdonisJS endpoint with mTLS using middleBrick’s BOLA/IDOR and Authentication checks can surface misconfigurations where IP-based rules are applied alongside certificate validation without proper network segmentation. The scanner’s unauthenticated attack surface testing can simulate rebinding-like conditions by probing whether internal IP assumptions are enforced independently of client certificates.
Remediation focuses on decoupling identity and network location. Treat mTLS client certificates as the sole source of identity, and avoid additional IP-based authorization unless enforced by network controls (e.g., firewall rules that cannot be bypassed via DNS). In AdonisJS, implement a request hook that validates the certificate subject or a custom claim and does not mix in IP checks for authorization decisions.
Mutual Tls-Specific Remediation in Adonisjs — concrete code fixes
To secure AdonisJS applications with mTLS and avoid DNS rebinding pitfalls, enforce strict identity-based authorization and avoid IP-derived trust. Below are concrete code examples demonstrating a robust mTLS setup using the @adonisjs/ssl provider and a custom request hook.
1. Configure mTLS in start/hooks.ts
Enable client certificate verification and load trusted CAs:
// start/hooks.ts
import { defineHook } from '@adonisjs/core'
import { createSslHook } from '@adonisjs/ssl'
export const ssl = defineHook(() => {
return createSslHook({
enabled: true,
requestCert: true,
rejectUnauthorized: true,
ca: [ /* PEM-encoded CA certificates */ `-----BEGIN CERTIFICATE-----
MIIBkTCB+wIJAKHHIgKwVGlHMA0GCSqGSIb3DQEBBQUAMAwxCzAJBgNVBAYTAlVT
... (truncated for brevity) ...
-----END CERTIFICATE-----`],
})
})
2. Create an authorization hook to validate client identity
Use a request hook to inspect the verified client certificate and set a consistent identity on the context, avoiding IP-based checks:
// start/hooks.ts
import { HttpContextContract } from '@adonisjs/core'
import { createAuthHook } from './auth/mtls_auth'
export const mtlAuth = createAuthHook((ctx: HttpContextContract) => {
const peerCert = ctx.ssl?.clientcert
if (!peerCert) {
throw new Error('Client certificate required')
}
// Extract subject or a custom SAN field for identity
const identity = extractIdentityFromCert(peerCert)
ctx.auth = { identity, scope: 'client' }
})
function extractIdentityFromCert(certPem: string): string {
// Use a library like @noble/hashes or node-forge to parse PEM
// Example: return parsedSubject.commonName or parsedSANs[0]
return 'extracted-identity'
}
3. Apply the hook globally or per route
Register the hook in start/kernel.ts and protect sensitive routes:
// start/kernel.ts
import { mtlAuth } from './hooks'
Route.group(() => {
Route.get('/api/admin/reset', 'AdminController.reset').middleware([mtlAuth])
}).prefix('api')
4. Example of insecure pattern to avoid
Do not combine mTLS with IP allowlists in application logic:
// ❌ Insecure: mixing cert and IP checks
if (sslClientCert && isTrustedIp(ctx.request.ip)) {
proceed()
}
5. Infrastructure-level protections
Ensure mTLS is enforced at the proxy or load balancer (e.g., NGINX, Envoy) and that the application only receives requests after successful client certificate validation. Do not rely on application-level IP checks when mTLS is in use.