Affected Versions
| Affected | not applicable (first-party code) |
| Fixed in | not applicable (first-party code) — see PR for fix commit |
| Ecosystem | N/A |
| CVE / GHSA | not assigned |
| CWE | CWE-287 (Improper Authentication) |
The Vulnerability Explained
The music studio application deployed an Express server with a localRequest middleware designed to restrict API access to localhost connections only. The intended security model was simple: if you're not connecting from the same machine, you shouldn't access song storage or voice-kit endpoints.
The original implementation validated only the HTTP Host header:
function localRequest(req, res, next) {
const host = req.headers.host;
if (!host || !/^(localhost|127\.0\.0\.1|\[::1\])(?::[0-9]{1,5})?$/.test(host)) {
return res.status(403).json({ error: '只接受本机地址访问' });
}
// ... continues to protected routes
}
The critical flaw: HTTP headers are attacker-controlled. The Host header is supplied by the client and can be set to localhost or 127.0.0.1 regardless of the actual TCP connection origin. The middleware never verified req.socket.remoteAddress, which reflects the actual network-layer source address.
An attacker could exploit this by:
1. Connecting to the exposed server from any remote IP address
2. Sending Host: localhost or Host: 127.0.0.1:3000 in the HTTP request
3. Passing the regex validation and gaining full API access
This bypass is particularly dangerous in containerized deployments (Docker, Kubernetes) where "localhost" inside a container is distinct from the host's localhost, and in multi-user systems where network namespaces might be shared.
The Fix
The patch adds explicit socket-level remote address validation before the Host header check:
function localRequest(req, res, next) {
const remote = req.socket?.remoteAddress;
if (!remote || !['127.0.0.1', '::1', '::ffff:127.0.0.1'].includes(remote)) {
return res.status(403).json({ error: '只接受本机地址访问' });
}
const host = req.headers.host;
if (!host || !/^(localhost|127\.0\.0\.1|\[::1\])(?::[0-9]{1,5})?$/.test(host)) {
return res.status(403).json({ error: '只接受本机地址访问' });
}
The fix introduces a defense-in-depth approach:
-
Socket address validation first:
req.socket.remoteAddressis kernel-provided and cannot be forged by HTTP header manipulation. The whitelist covers IPv4 localhost (127.0.0.1), IPv6 localhost (::1), and the IPv4-mapped IPv6 form (::ffff:127.0.0.1) that Node.js commonly reports. -
Preserved Host header check: The original validation remains as a secondary check, catching edge cases where socket address might be misleading (though unlikely for localhost).
-
Early return: Both checks fail fast with the same 403 response, preventing any downstream middleware or route handlers from executing on unauthorized requests.
Key Takeaways
- Never trust HTTP headers for security decisions about connection origin: The
Hostheader,X-Forwarded-For, and similar headers are client-supplied and trivially spoofed. Always validatereq.socket.remoteAddressor equivalent kernel-reported addresses for localhost restrictions. - IPv6 has multiple localhost representations: The fix must account for
::1,::ffff:127.0.0.1, and potentially127.0.0.0/8variants. Node.js's representation varies by binding configuration. - "Local-only" applications often escape their boundaries: Container networking, reverse proxies, and development tunnels can expose supposedly local services. Design authentication mechanisms that survive these transitions.
- Middleware ordering matters: The
localRequestvalidation runs before route handlers, but if any earlier middleware (error handlers, logging) executes first, it might leak information or accept malformed requests.
How Orbis AppSec Detected This
Source: The req.headers.host HTTP request parameter (attacker-controlled header)
Sink: The localRequest middleware function that gates access to createSongStore and mountVoiceKit API endpoints
Missing control: No validation of req.socket.remoteAddress before processing the request; the middleware relied solely on forgeable Host header pattern matching
CWE: CWE-287 — Improper Authentication
Fix: Added explicit whitelist check of req.socket.remoteAddress against ['127.0.0.1', '::1', '::ffff:127.0.0.1'] before Host header validation
Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.
Conclusion
This vulnerability demonstrates how a seemingly robust localhost restriction can collapse when implemented at the wrong abstraction layer. The original localRequest middleware looked correct—until you realize it validates user input rather than network reality. For applications designed to run locally, the req.socket.remoteAddress check added in this fix provides the actual security boundary that HTTP headers cannot.