Ssrf Server Side in Adonisjs with Mutual Tls
Ssrf Server Side in Adonisjs with Mutual Tls — how this specific combination creates or exposes the vulnerability
Server-side request forgery (SSRF) in AdonisJS when mutual TLS (mTLS) is used centers on how the framework handles outbound HTTP requests and TLS material. AdonisJS relies on an underlying HTTP client (often an axios-based wrapper) to perform external calls. If those calls are built from unchecked user input—such as a webhook URL, file import endpoint, or dynamic API base URL—an attacker can supply a target that resolves inside the server-side network, bypassing expectations about public internet destinations.
Mutual TLS introduces client certificates and private keys into the equation. In AdonisJS, you typically configure an HTTP client with TLS options that include key and certificate paths. When mTLS is set up, the client presents a certificate to the target; if the application logic does not strictly validate the destination before establishing the TLS handshake, an attacker can point the request to an internal service that also expects mTLS. Internal services often trust the client certificate presented by AdonisJS because it originates from a trusted CA, enabling the SSRF to reach otherwise unreachable endpoints such as metadata services (e.g., http://169.254.169.254), internal gRPC bridges, or admin interfaces on non-routable IPs.
Another vector is the misuse of mTLS configuration itself. AdonisJS code that loads key/cert paths from environment variables and then reuses them across dynamic outbound calls can inadvertently allow an attacker to influence the TLS behavior. For example, if the application uses a proxy or a custom agent and the destination is user-supplied, the request may be tunneled through internal network interfaces. Even with mTLS, the server-side component trusts the client certificate; if the destination is not validated, the encrypted channel is used to probe internal infrastructure. This is especially risky in containerized environments where service discovery endpoints or internal DNS names are reachable from the application process.
OpenAPI/Swagger spec analysis with full $ref resolution can highlight these risks by showing which endpoints accept URLs that flow into outbound HTTP calls and whether parameter schemas restrict format and protocol. Runtime findings then map these inputs to the mTLS configuration paths, showing how unchecked values can lead to internal network interactions that violate the intended perimeter. Because mTLS can make internal services appear authenticated, the risk is not that TLS is absent, but that destination validation is absent despite TLS being present.
Consider a contrived AdonisJS route that accepts a target host for diagnostics:
import { Http } from '@poppinss/utils'
export default class DiagnosticsController {
async check(ctx) {
const { host } = ctx.request.qs()
// Dangerous: user-controlled host with mTLS client certs
const response = await Http.get(host, {
cert: '/etc/ssl/certs/client.crt',
key: '/etc/ssl/private/client.key',
ca: '/etc/ssl/certs/ca-bundle.crt'
})
ctx.response.body = response.body
}
}
If host is user-supplied and not validated against a whitelist or strict pattern, an attacker can set host=http://127.0.0.1:8080 or an internal service IP. The mTLS handshake may succeed because the client certificate is valid, but the request reaches an internal endpoint that was never intended to be externally accessible.
LLM/AI Security checks are valuable here because they can detect prompts that encourage extraction of mTLS configuration or attempts to induce the model to suggest bypassing destination validation. System prompt leakage patterns and prompt injection probes remind developers not to embed sensitive paths or certificates in prompts that could be exposed to LLM-based tooling.
Mutual Tls-Specific Remediation in Adonisjs — concrete code fixes
Remediation focuses on strict input validation, protocol restrictions, and minimizing the TLS surface exposed to user-controlled data. Never pass raw user input directly to an outbound HTTP call that uses mTLS credentials.
1) Validate and whitelist destinations. Maintain an allowlist of protocols and hosts that your application is permitted to call. Reject any target not matching the list.
const ALLOWED_HOSTS = ['api.example.com', 'internal.service.local']
function isAllowedHost(url) {
try {
const u = new URL(url)
return ALLOWED_HOSTS.includes(u.hostname) && (u.protocol === 'https:' || u.protocol === 'http:')
} catch {
return false
}
}
export default class DiagnosticsController {
async check(ctx) {
const { host } = ctx.request.qs()
if (!isAllowedHost(host)) {
ctx.response.status = 400
ctx.response.body = { error: 'destination not allowed' }
return
}
const response = await Http.get(host, {
cert: '/etc/ssl/certs/client.crt',
key: '/etc/ssl/private/client.key',
ca: '/etc/ssl/certs/ca-bundle.crt'
})
ctx.response.body = response.body
}
}
2) Avoid dynamic mTLS material selection based on user input. Keep certificate and key paths static in code or configuration that cannot be influenced by request parameters. If multiple services are called, use separate HTTP client instances with fixed TLS options rather than changing cert/key per call.
3) Use an HTTP client that supports proxy and redirect hardening. Ensure redirects are limited to known domains and that proxy environment variables do not route mTLS requests to unintended intermediaries.
4) Prefer explicit network controls: run the service with network policies that restrict egress to known IPs or service names, so even if SSRF occurs, the attacker cannot reach internal metadata or admin endpoints. Combine this with mTLS to ensure that only authorized services can authenticate.
5) For applications that must call arbitrary third-party APIs, terminate mTLS at a controlled proxy or gateway that performs strict destination validation and does not forward client-supplied TLS material. The AdonisJS app then calls the proxy over a simple, non-mTLS channel, reducing the risk that user input can direct the TLS handshake toward internal services.
middleBrick scans can validate these mitigations by checking your OpenAPI/Swagger spec for overly permissive parameters and by testing runtime behavior against SSRF indicators. The findings include remediation guidance mapped to frameworks such as OWASP API Top 10 and can be integrated into your workflow via the CLI with middlebrick scan <url>, the GitHub Action for CI/CD gates, or the MCP Server in your IDE.