Ssrf Server Side in Express with Basic Auth
Ssrf Server Side in Express with Basic Auth — how this specific combination creates or exposes the vulnerability
Server-side request forgery (SSRF) in an Express application that uses HTTP Basic Authentication can expose internal services and bypass access controls that rely on network-level restrictions. When an endpoint accepts a user-supplied URL and makes an HTTP request on the server, the server-side request does not automatically inherit the client’s credentials. However, if the Express route is designed to forward requests on behalf of authenticated users and the destination URL points to internal or cloud metadata services, SSRF becomes possible. The presence of Basic Auth on the public endpoint does not protect the internal targets, because the server acts as the client and may have broader network reach than the authenticated user.
For example, an endpoint intended to fetch a user-provided URL might resolve internal hostnames like http://169.169.254.169 (AWS instance metadata) or internal Kubernetes services such as http://kubernetes.default.svc. If the Express route does not enforce strict URL allowlists or network egress controls, the server can be tricked into making requests to these internal endpoints. Attack patterns like this are cataloged in the OWASP API Top 10 (e.g., API1:2023 Broken Object Level Authorization) and can lead to data exposure, lateral movement, or metadata service credential harvesting. Tools like middleBrick can detect SSRF through its dedicated SSRF check, which tests whether the API permits requests to internal or unexpected destinations and reports findings with severity guidance and remediation steps.
In a black-box scan, middleBrick tests the unauthenticated attack surface and can identify SSRF behavior even when Basic Auth protects the public-facing endpoint. This is because the scanner evaluates whether the API reflects or leaks internal network information in responses, and whether it allows resolution of private IP ranges or cloud metadata endpoints. Because SSRF is fundamentally a server-side trust issue, the authentication mechanism applied at the API gateway does not mitigate the core risk: the server making arbitrary requests on behalf of the client.
Basic Auth-Specific Remediation in Express — concrete code fixes
To mitigate SSRF in Express when using Basic Authentication, focus on input validation, network egress controls, and safe request handling. Do not rely on Basic Auth to protect internal services; instead, enforce strict allowlists for hostnames and IP ranges, and avoid forwarding requests to user-supplied URLs when possible. When forwarding is required, use a tightly scoped HTTP client with a configured proxy and explicit network policies.
Below are concrete Express examples. The first shows a vulnerable pattern where user input is passed directly to an HTTP request. The second shows a hardened approach with hostname validation and no blind forwarding.
Vulnerable Express route with Basic Auth
const express = require('express');
const basicAuth = require('express-basic-auth');
const axios = require('axios');
const app = express();
app.use('/public', basicAuth({
users: { 'alice': 'secret123' },
challenge: true
}), express.json());
app.get('/public/proxy', async (req, res) => {
const { url } = req.query; // user-controlled
try {
const response = await axios.get(url); // SSRF risk
res.json({ data: response.data });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.listen(3000);
Hardened Express route with hostname allowlist
const express = require('express');
const basicAuth = require('express-basic-auth');
const axios = require('axios');
const { URL } = require('url');
const app = express();
app.use('/public', basicAuth({
users: { 'alice': 'secret123' },
challenge: true
}), express.json());
const ALLOWED_HOSTS = new Set(['api.example.com', 'internal.service.local']);
function isAllowedHost(hostname) {
return ALLOWED_HOSTS.has(hostname);
}
app.get('/public/proxy', async (req, res) => {
const { url } = req.query;
if (!url) {
return res.status(400).json({ error: 'url query parameter required' });
}
let parsed;
try {
parsed = new URL(url);
} catch (err) {
return res.status(400).json({ error: 'invalid url' });
}
if (!isAllowedHost(parsed.hostname)) {
return res.status(403).json({ error: 'hostname not allowed' });
}
try {
// Optionally set timeouts and disable redirects
const response = await axios.get(parsed.toString(), {
maxRedirects: 0,
timeout: 5000,
validateStatus: null
});
res.json({ data: response.data, status: response.status });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.listen(3000);
Additional measures include restricting outbound network access at the container or host level, using environment-based proxy settings, and avoiding the use of user-supplied ports. For ongoing assurance, integrate middleBrick’s CLI or GitHub Action to scan your Express APIs on a schedule; the Pro plan supports continuous monitoring and CI/CD integration that can fail builds if risk scores exceed your defined thresholds.