Ssrf in Adonisjs with Mutual Tls
Ssrf 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 arises from a mismatch of trust boundaries. AdonisJS applications often make outbound HTTP requests to internal or third‑party services. If user‑controlled data (e.g., a URL or host header) is used to drive those requests without strict validation, an attacker can force the server to reach unintended hosts. Enabling mTLS adds client certificate authentication for inbound requests to your AdonisJS app, but it does not automatically secure outbound calls. Attackers can abuse internal endpoints that expect mTLS client certificates, bypassing perimeter network controls, reaching metadata services, or pivoting to services only accessible to mTLS‑authenticated clients.
Consider an AdonisJS route that accepts a target hostname and path, then forwards a request using the application’s TLS client. If the hostname is supplied by the user and the HTTP client does not validate the resolved host against a strict allowlist, an attacker can supply an internal address (e.g., 169.254.169.254 for cloud metadata) or a service name reachable only with mTLS. Because mTLS is enforced on the inbound side only, the outbound request may still succeed using the application’s configured certificate and key, effectively chaining two controls: inbound mTLS authentication for your app and outbound mTLS expectations from the target. This can expose internal services that are otherwise invisible from the public network, increasing the impact of SSRF.
Real-world examples align with common OWASP API Top 10 and CWE categories. For instance, an ad-hoc HTTP client in AdonisJS might look like this:
import { Http } from '@adonisjs/core/build/standalone';
export async function fetchExternal(url: string) {
return await Http.get(url, {
timeout: 5000,
});
}
If url is derived from user input and the target service requires mTLS (or simply accepts requests from your app’s outbound IP), SSRF becomes viable. An attacker could provide a URL like https://169.254.169.254/latest/meta-data/iam/security-credentials/, causing the AdonisJS server to leak instance metadata. The presence of mTLS on your inbound endpoint does not prevent this; it only ensures the caller presented a valid client certificate. Outbound requests may not enforce equivalent hostname or certificate pinning, enabling the SSRF chain.
Additionally, header-based SSRF can occur when the application forwards incoming headers (e.g., x-forwarded-proto or x-host) to downstream services that trust mTLS client certificates. AdonisJS’s built-in validation utilities should be used to enforce strict allowlists for hosts and ports, and to reject requests that reference internal RFC1918 or cloud metadata ranges.
To detect this pattern using middleBrick, you can submit your AdonisJS endpoint URL. The scanner will exercise input validation, SSRF, and other checks, mapping findings to frameworks such as OWASP API Top 10 and providing remediation guidance. Note that middleBrick detects and reports these issues; it does not fix or block them.
Mutual Tls-Specific Remediation in Adonisjs — concrete code fixes
Mitigating SSRF in AdonisJS while preserving mTLS involves three layers: strict input validation, safe HTTP client configuration, and certificate pinning where feasible. Below are concrete, syntactically correct examples.
1) Validate and restrict target URLs using an allowlist approach. Never forward user input directly to arbitrary hosts:
import { Http } from '@adonisjs/core/build/standalone';
import { schema, rules } from '@ioc:Adonis/Core/Validator';
const allowedHosts = new Set(['api.partner.com', 'internal.service.local']);
const urlSchema = schema.create({
target: schema.string({}, [
rules.url({ trim: true }),
rules.normalizeUrl(),
(_, value) => {
try {
const u = new URL(value);
if (!allowedHosts.has(u.hostname)) {
throw new Error('Hostname not allowed');
}
} catch {
throw new Error('Invalid URL');
}
},
]),
});
export async function fetchValidated(url: string) {
const payload = await schema.validate({ url }, urlSchema);
return await Http.get(payload.url, { timeout: 5000 });
}
2) Configure the HTTP client to enforce certificate and hostname checks. AdonisJS uses native HTTP clients under the hood; you can pass agent options or use a custom agent to pin certificates:
import { Http } from '@adonisjs/core/build/standalone';
import https from 'https';
const agent = new https.Agent({
cert: fs.readFileSync('/path/client-cert.pem'),
key: fs.readFileSync('/path/client-key.pem'),
ca: fs.readFileSync('/path/ca-bundle.pem'),
checkServerIdentity: (hostname, cert) => {
// Pin expected certificate fingerprint or SAN
const expectedFingerprint = 'aa:bb:cc:dd...';
const actualFingerprint = cert.fingerprint.replace(/[^a-f0-9]/gi, '').toLowerCase();
if (actualFingerprint !== expectedFingerprint) {
return new Error('Certificate pinning mismatch');
}
return undefined;
},
});
export async function fetchWithPinning(url: string) {
return await Http.get(url, { timeout: 5000, https: { agent } });
}
3) Enforce outbound mTLS by ensuring your application’s TLS credentials are scoped and rotated. Avoid using the same client certificate for all outbound calls; instead, bind certificates to specific services or identities. Combine this with network policies that restrict which internal endpoints your application can reach, reducing the blast radius of a potential SSRF.
4) Use environment-based configuration to separate inbound and outbound TLS settings. For example, keep inbound mTLS verification in start/server.ts and manage outbound client options via environment variables or service discovery, ensuring that development and production profiles differ in strictness.
middleBrick’s Pro plan supports continuous monitoring and CI/CD integration, enabling you to fail builds if risk scores exceed your threshold. This complements remediation by catching regressions early. The GitHub Action can be added to your pipeline to enforce security gates before deployment.
Related CWEs: ssrf
| CWE ID | Name | Severity |
|---|---|---|
| CWE-918 | Server-Side Request Forgery (SSRF) | CRITICAL |
| CWE-441 | Unintended Proxy or Intermediary (Confused Deputy) | HIGH |