Ssrf Server Side in Adonisjs with Api Keys
Ssrf Server Side in Adonisjs with Api Keys — how this specific combination creates or exposes the vulnerability
Server-side request forgery (SSRF) in AdonisJS when API keys are used for outbound calls can amplify exposure of internal services and bypass network-level restrictions. API keys are often stored in environment variables and passed in headers or query parameters. If an attacker can influence the target URL of an HTTP request made by the server—while those requests include the trusted API key—they can force the AdonisJS application to relay requests to internal endpoints that the key has permission to access.
In AdonisJS, HTTP clients are commonly configured with default headers, including authorization tokens. For example, a developer might set a global header for an HTTP client used to call third-party services:
import { Http } from '@adonisjs/core/build/standalone';
const api = Http.client()
.timeout(5000)
.headers({ Authorization: `Bearer ${process.env.EXTERNAL_API_KEY}` });
If this api instance is then used to make requests to a user-supplied URL without strict validation, an attacker can supply an internal address such as http://169.254.169.254/latest/meta-data/ (AWS metadata service) or internal Kubernetes services like http://kubernetes.default.svc. Because the request carries the trusted API key, the backend may successfully reach internal endpoints that would normally be unreachable from outside the network. This combination turns a typical SSRF into an internal reconnaissance or lateral movement path.
AdonisJS applications that also integrate LLM endpoints or proxy services are especially at risk: an SSRF can lead to unauthenticated LLM endpoint detection or data exfiltration if the proxied calls include API keys. Insecure deserialization or dynamic URL construction—such as using a parameter to build a webhook URL—can compound the issue. For example:
// Risky: user-controlled URL used directly
const target = ctx.request.input('webhookUrl');
await api.post('/forward').send({ url: target, data: payload });
Without validating or sanitizing target, the application can be tricked into relaying requests into internal management interfaces. Because API keys grant elevated permissions, the impact can extend to data exposure, privilege escalation, or unauthorized invocation of internal APIs.
Api Keys-Specific Remediation in Adonisjs — concrete code fixes
Remediation focuses on limiting what the API key can reach and ensuring user input never directly controls internal targets. Follow these practices in AdonisJS:
- Never forward user-supplied URLs to an HTTP client that already carries an API key. Instead, implement an allowlist of permitted domains or use a proxy endpoint that maps friendly aliases to pre-approved destinations.
- Restrict outbound connectivity by network policy and validate URLs strictly. Use a URL parser to enforce allowed protocols and hosts.
- Scope API keys to specific endpoints and avoid broad permissions. Rotate keys regularly and avoid storing them in code or logs.
Secure coding example: validate and resolve the target against an allowlist before making authenticated requests:
import { Http } from '@adonisjs/core/build/standalone';
import { UrlObject } from 'url';
const ALLOWED_HOSTS = new Set(['api.example.com', 'webhook.service.com']);
async function makeSafeRequest(userPath: string, payload: any) {
const parsed = new URL(userPath, 'https://example.com');
if (!ALLOWED_HOSTS.has(parsed.hostname)) {
throw new Error('Destination not allowed');
}
const api = Http.client()
.timeout(5000)
.headers({ Authorization: `Bearer ${process.env.EXTERNAL_API_KEY}` });
const response = await api.post(parsed.toString()).send(payload);
return response.body;
}
If you must accept dynamic targets (for example, in integration workflows), use a proxy that does not include API keys and enforce strict schema validation:
import { schema } from '@ioc:Adonis/Core/Validator';
const webhookSchema = schema.create({
target: schema.string({}, [
(value) => {
const u = new URL(value);
if (!u.hostname.endsWith('.trusted-partner.com')) {
throw new Error('invalid domain');
}
},
]),
data: schema.object({}),
});
const validated = await validator.validate({ schema: webhookSchema, data: ctx.request.all() });
// Forward without exposing API keys: use a backend-to-backend token or session auth instead
const response = await Http.post(validated.target, validated.data);
For integrations with LLM endpoints or external AI services, prefer short-lived tokens and ensure SSRF checks include metadata service IPs and internal Kubernetes DNS names. MiddleBrick can support this posture by scanning your endpoints for SSRF and API-key exposure patterns, helping you prioritize fixes based on severity and mapping findings to frameworks such as OWASP API Top 10.