Ssrf Server Side in Express with Bearer Tokens
Ssrf Server Side in Express with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Server-side request forgery (SSRF) in Express APIs that accept and forward HTTP requests—such as webhooks or outbound calls to internal metadata or cloud services—becomes more complex and dangerous when Bearer tokens are involved. An API endpoint that routes requests to a user-supplied URL may inadvertently allow an attacker to direct traffic from the server to internal services that expect Bearer authentication. Because the backend holds or can obtain a valid token (for example from environment variables or a secrets manager), the attacker can force the server to make authenticated requests to internal endpoints that are not exposed on the public internet, bypassing network-level isolation.
Consider an Express route that accepts a URL to fetch or proxy. If the route implementation does not validate or restrict the destination, an attacker can supply an internal address such as http://169.254.169.254/latest/meta-data/iam/security-credentials/ (AWS instance metadata) or an internal Kubernetes service URL. When the server performs the request, it may add an Authorization header containing a Bearer token sourced from server-side configuration. The SSRF vector thus becomes an authenticated channel to internal systems. Common triggers include XML External Entity (XXE) injection in XML payloads, unsafe URL parsing, or redirects that the server follows without restriction. The presence of Bearer tokens does not cause SSRF by itself, but it removes a key barrier and turns an otherwise low-severity SSRF into a high-severity finding, since the server can act on behalf of the application with privileged credentials.
In practice, this risk maps to the BFLA/Privilege Escalation and SSRF checks in middleBrick’s scan set. The scanner tests whether an endpoint that accepts a target URL can force the server to reach internal or metadata endpoints, and whether sensitive headers such as Authorization are forwarded or leaked. Because SSRF often relies on following redirects or exploiting XML/JSON parsing, it is important to validate and sanitize inputs, enforce strict destination allowlists, and avoid forwarding sensitive authentication headers to user-controlled destinations.
Bearer Tokens-Specific Remediation in Express — concrete code fixes
To mitigate SSRR in Express while handling Bearer tokens, ensure that user input never dictates the destination of authenticated requests. Below are concrete, safe patterns for Express that prevent leaking Bearer tokens to untrusted hosts.
1) Validate and restrict destination URLs
Use a strict allowlist of domains or paths and reject any URL that does not match. Do not rely on host header manipulation or client-supplied paths.
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', 'internal.example.com']);
function isAllowedHost(inputUrl) {
try {
const parsed = new URL(inputUrl);
return ALLOWED_HOSTS.has(parsed.hostname);
} catch (err) {
return false;
}
}
app.post('/fetch', async (req, res) => {
const { url } = req.body;
if (!url || !isAllowedHost(url)) {
return res.status(400).json({ error: 'Invalid or disallowed destination' });
}
try {
const response = await axios.get(url, {
headers: {
Authorization: `Bearer ${process.env.BEARER_TOKEN}`
},
timeout: 5000,
// Prevent following redirects to internal destinations
maxRedirects: 0
});
res.json(response.data);
} catch (err) {
res.status(err.response?.status || 500).json({ error: 'Request failed' });
}
});
app.listen(3000, () => console.log('Server running on port 3000'));
2) Do not forward incoming Authorization headers
If your API receives an Authorization header from a client, do not propagate it to the destination when the destination is user-controlled. This prevents token leakage and SSRF-assisted access to authenticated internal endpoints.
app.post('/proxy-safe', async (req, res) => {
const { targetUrl } = req.body;
if (!targetUrl || !isAllowedHost(targetUrl)) {
return res.status(400).json({ error: 'Invalid target' });
}
// Use a service-specific token from server-side config, not from the client
const serverToken = process.env.SERVICE_BEARER_TOKEN;
try {
const response = await axios.get(targetUrl, {
headers: {
Authorization: `Bearer ${serverToken}`
// Intentionally omitting any Authorization from req.headers
},
validateStatus: () => true
});
res.json({ status: response.status, data: response.data });
} catch (err) {
res.status(502).json({ error: 'Upstream error' });
}
});
3) Handle XML and JSON parsing safely
SSRF can be triggered via XML External Entity (XXE) injection if your app parses XML. Disable external entities and DTDs. For JSON, avoid passing raw user input into parsers that resolve references or $ref to external URLs without validation.
const libxmljs = require('libxmljs');
app.post('/xml', (req, res) => {
const xml = req.body.xml;
try {
// Parse with external entities disabled
const doc = libxmljs.parseXml(xml, { noent: false, noblanks: false, processEntities: false });
res.json({ ok: true });
} catch (err) {
res.status(400).json({ error: 'Invalid XML' });
}
});
4) Use network controls and secrets management
Run your Express service in an environment with network restrictions (e.g., no public outbound access to internal IP ranges) and retrieve Bearer tokens from a secrets manager at runtime rather than embedding them in code. This reduces the blast radius if SSRF is introduced inadvertently.
5) Scan to validate mitigations
Use middleBrick’s CLI to verify that your remediation works as intended. For example, after applying the above fixes, run:
middlebrick scan https://your-api.example.com/fetch
Review the report to confirm that internal hosts and metadata endpoints are not reachable and that no unauthorized Bearer token usage is detected.