Ssrf Server Side in Express with Api Keys
Ssrf Server Side in Express with Api Keys — how this specific combination creates or exposes the vulnerability
Server-side request forgery (SSRF) in an Express service that uses API keys can arise when the application accepts a user-supplied target URL and forwards it with an upstream API key in headers or query parameters. If the destination is user-controlled and the API key is passed through without validation or network segregation, an attacker can direct the server to internal endpoints that are normally protected by network-level access controls. For example, an Express route that fetches a webhook URL provided by the client and adds an Authorization header containing a service API key can be abused to probe internal metadata services or internal APIs by supplying URLs such as http://169.254.169.254/latest/meta-data/ on AWS or internal Kubernetes services.
The exposure is compounded when the API key is treated as a credential that the backend safely manages, while the SSRF vector allows the attacker to leverage that credential against arbitrary internal hosts. Even if the Express app validates that the URL uses HTTP or HTTPS, an attacker can still reach internal addresses via encoded formats, DNS rebinding, or alternative schemes when the networking perimeter is not enforced. Because SSRF targets the server’s outbound path, the API key does not mitigate the ability to reach unintended internal services; instead, the key may be harvested if the SSRF response includes credentials or tokens, or it may be used to perform authenticated actions on internal systems.
In an API security scan, such patterns are identified through checks that correlate input validation weaknesses with outbound HTTP functionality and exposed authentication material. The scan examines whether user data flows into the request target and into headers that include API keys without sufficient allowlisting or network isolation. This is especially important when the API key is intended for a third-party service but the endpoint used to call that service is constructed from unvalidated input, creating a scenario where the key is usable from unexpected network locations.
Api Keys-Specific Remediation in Express — concrete code fixes
To reduce SSRF risk when using API keys in Express, control the destination host and port explicitly, avoid concatenating user input into the request target, and ensure that API keys are not inadvertently exposed to user-influenced destinations. Below are concrete, safe patterns for Express routes that call external services with API keys.
1) Strict host allowlisting and URL parsing
Instead of using the user-supplied URL directly, parse the URL, validate the hostname against an allowlist, and reconstruct a safe request target. This prevents redirects to internal IPs or unintended schemes.
const express = require('express');
const axios = require('axios');
const { URL } = require('url');
const app = express();
app.use(express.json());
const ALLOWED_HOSTS = new Set(['api.example.com', 'data.example.com']);
const API_KEY = process.env.EXTERNAL_API_KEY; // stored securely
app.post('/proxy', async (req, res) => {
try {
const target = new URL(req.body.url);
if (!ALLOWED_HOSTS.has(target.hostname)) {
return res.status(400).json({ error: 'Destination host not allowed' });
}
const response = await axios.get(target.toString(), {
headers: { Authorization: `Bearer ${API_KEY}` },
timeout: 5000,
});
res.json(response.data);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.listen(3000, () => console.log('Server running on port 3000'));
2) Using a backend connector with a fixed endpoint and header-only key injection
When the target service is known and fixed, avoid accepting a full URL entirely. Use a static endpoint and inject the API key only via headers. This removes SSRF entirely while still using API keys for authentication.
const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
const FIXED_ENDPOINT = 'https://api.example.com/v1/resource';
const API_KEY = process.env.EXTERNAL_API_KEY;
app.get('/resource', async (req, res) => {
try {
const response = await axios.get(FIXED_ENDPOINT, {
headers: { 'X-API-Key': API_KEY },
});
res.json(response.data);
} catch (err) {
res.status(500).json({ error: 'Failed to fetch resource' });
}
});
app.listen(3000, () => console.log('Server running on port 3000'));
3) Defense-in-depth measures
- Set outbound network policies so that the Express host cannot reach internal metadata or sensitive ranges (e.g., 169.254.0.0/16, 127.0.0.0/8, internal RFC1918 blocks).
- Do not log full responses that may contain API keys or tokens; sanitize logs.
- Rotate API keys regularly and scope them to least privilege and, if supported, to specific source IPs or VPC endpoints.
These patterns ensure that API keys remain tied to intended external services and are not usable from arbitrary destinations an attacker might force the server to reach.