Jun 17, 2026·7 min read·19 visits
A path parsing discrepancy between Node's URL parser and the raw string checks in the 'ws' library allows proxy middleware in webpack-dev-server to intercept local HMR WebSocket traffic. This bypasses Host/Origin security controls and leaks client cookies to proxy targets.
webpack-dev-server (WDS) is vulnerable to an Origin Validation Error (CWE-346) and a Confused Deputy vulnerability (CWE-441) due to path normalization discrepancies in its upgrade handling. When a proxy is configured with a broad context and WebSocket support is enabled, the proxy middleware intercepts internal Hot Module Replacement (HMR) WebSocket upgrade requests. This forwards the browser's credentials (such as Cookies and Origin headers) to the backend target, bypassing built-in security controls and corrupting the WebSocket connection.
The front-end utility webpack-dev-server (WDS) is an HTTP-based development server designed to host local web applications. It implements a Hot Module Replacement (HMR) framework to dynamically inject code updates into running applications without requiring full page refreshes. Communication between the browser client and the local compilation runner relies on a dedicated WebSocket interface. By default, this socket executes on specific local paths, such as /ws or /sockjs-node depending on the configured version.
To facilitate integration with backend components, developers often configure a local reverse proxy using the devServer.proxy directive. This proxy is powered by the http-proxy-middleware engine and runs on the same underlying HTTP server instance. When a developer creates a wildcard or broad proxy configuration (such as proxying the root path / with WebSocket support enabled via ws: true), the proxy's upgrade handlers are bound globally to the server. Without strict isolation, the proxy interceptor can hijack the internal development server's own HMR socket upgrades.
This vulnerability occurs because the pre-filter mechanism in WDS fails to reliably identify and bypass HMR requests before they are routed to the user-configured proxy. By intercepting these internal frames, WDS acts as a confused deputy. It forwards local administrative WebSocket handshake packets directly to the configured backend target. This action bypasses the Host header check and CORS validation layers built directly into WDS.
The root cause of this vulnerability lies in a critical path-normalization discrepancy between two software layers: the pre-filter router in webpack-dev-server and the route matcher in the underlying ws library. When a client initiates a WebSocket connection, an HTTP GET request containing Upgrade: websocket headers is dispatched to the server. The WDS middleware evaluates whether the request matches the local Hot Module Replacement path (hmrPath) to decide if it must skip proxying.
In versions prior to 5.2.5, WDS extracted the request path from the incoming message using Node.js's native URL class. This parser normalizes URL sequences. Specifically, it resolves relative path steps, collapses duplicate adjacent slashes (e.g., rewriting //ws to / under certain hostname configurations), decodes percent-encoded character sequences, and strips trailing forward slashes. This normalization behavior is standard for general web servers but differs from low-level protocol drivers.
The underlying ws WebSocket library (specifically inside its WebSocketServer#shouldHandle method) does not normalize incoming paths. Instead, it performs a strict, raw, case-sensitive comparison of the raw string stored in req.url with the query string manually stripped. It does not normalize duplicate slashes, decode percent encodings, or ignore case variants. Consequently, a request sent to //ws, /%77%73, or /WS fails the raw comparison inside ws, but is normalized to /ws by the pre-filter URL parser. This path mismatch allows malicious or deformed client requests to evade the pre-filter and get captured by the broader proxy middleware, or to trigger a dual-upgrade handler race condition.
In versions of webpack-dev-server prior to 5.2.5, the upgrade pre-filter used the standard URL constructor to parse the path. The vulnerable implementation resolved paths as follows:
// Vulnerable routing block inside lib/Server.js
const { pathname } = new URL(req.url, "http://0.0.0.0");
if (pathname === hmrPath) {
return; // Skip proxying and let the local WebSocket server handle it
}
// If the path was modified (e.g. //ws), pathname became "/" and missed the block
proxyUpgrade(req, socket, head);This logic causes a parsing differential. Because new URL('//ws', 'http://0.0.0.0') is parsed with ws treated as the hostname and / as the path, pathname resolves to /. Since / does not match hmrPath (which is typically /ws), the filter does not return early. Instead, the request drops down to proxyUpgrade(). However, the raw req.url is still string-matched against the proxy targets.
To address this discrepancy, the maintainers in commit 948d5e6089bebcd801dac2cbe3ed4f80b64f117a removed the URL parser entirely. They aligned the string extraction mechanism exactly with the native parsing behavior of the ws library:
// Patched upgrade handling in lib/Server.js (v5.2.5)
(this.server).on("upgrade", (req, socket, head) => {
if (hmrPath && typeof req.url === "string") {
// Extract the raw path prefix up to the query delimiter
const queryIndex = req.url.indexOf("?");
const pathname =
queryIndex !== -1 ? req.url.slice(0, queryIndex) : req.url;
// Match the exact raw character sequence processed by the ws library
if (pathname === hmrPath) {
return; // Early return correctly blocks the proxy handler
}
}
proxyUpgrade(req, socket, head);
});This simple slice operation guarantees that WDS only blocks the proxy when the string matches the exact format that the ws library will accept. Any invalid or variant paths that would be ignored by ws are consistently left to the proxy, preventing dual-handling on mismatched paths.
An attack occurs when a client browser connects to a webpack-dev-server instance configured with a wildcard or broad proxy path, such as / with ws: true. When WDS receives a client connection attempting an upgrade to the HMR socket, the proxy middleware intercepts the HTTP handshake. Because the pre-filter parsing is bypassed, the proxy processes the upgrade and forwards the entire request payload to the designated backend server target.
This forwarding behavior creates an information disclosure vector. The proxy forwards the browser client's cookies (including HttpOnly session tokens) and the Origin header directly to the backend target. Under normal circumstances, these credentials should remain restricted to the local development server context. This allows any unauthenticated or unauthorized backend proxy target to receive credentials intended solely for the local environment.
Additionally, this bypass neutralizes the dev-server's built-in Host and Origin validation checks. These checks prevent Cross-Origin WebSocket Hijacking (COSH) and DNS rebinding attacks. Because the proxy captures the connection before the server applies validation rules, those security checks are bypassed. Finally, if the request is accepted by both the local HMR WebSocket server and the proxy middleware, both systems attempt to write handshake headers and upgrade frames to the same TCP socket. This dual-handling violates RFC 6455 and immediately corrupts the stream, leading to connection failures and development server instability.
To fully resolve CVE-2026-9595, users should upgrade webpack-dev-server to version 5.2.5 or higher. This update changes the HMR path-matching logic to match the exact string processing used by the ws dependency, resolving the parsing differential.
For systems where an immediate upgrade is not feasible, developers must configure mitigation strategies to reduce exposure. The most effective mitigation is to narrow the scope of the proxy middleware's routing contexts. Wildcard contexts (such as /) should be avoided. Instead, define specific prefix paths to ensure that the proxy only captures designated backend routes:
// Remediated Proxy Configuration with restricted paths
module.exports = {
devServer: {
proxy: [
{
context: '/api',
target: 'http://localhost:3000',
ws: false
}
]
}
};If the application does not rely on backend WebSocket services, the proxy's socket integration should be disabled by setting the ws parameter to false (or omitting it). This prevents the proxy from binding to the HTTP server's upgrade event emitter, blocking the attack vector.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
webpack-dev-server webpack | < 5.2.5 | 5.2.5 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-346, CWE-441 |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 Score | 5.3 (Medium) |
| EPSS Score | 0.00163 (Percentile: 5.81%) |
| Impact | Credential Leakage, Host Security Bypass, Connection Corruption |
| Exploit Status | poc |
| KEV Status | Not Listed |
The software does not properly validate or normalizes the origin of a request, or improperly forwards transactions to downstream hosts on behalf of a client without checking validation rules.
An authentication bypass in the SiYuan personal knowledge management system before version 3.7.0 exposes a dynamic icon rendering endpoint. This endpoint processes client-supplied Go template directives. By submitting a crafted request, an unauthenticated remote attacker can leverage registered database template functions to execute arbitrary read-only SQL queries and exfiltrate workspace contents.
CVE-2026-54069 is a critical authentication bypass vulnerability in the SiYuan Note personal knowledge management system. The flaw is located in the HTTP server's middleware handling API authorization, which unconditionally trusts requests carrying a 'chrome-extension://' scheme in the Origin HTTP header, granting administrative access without validating API tokens.
CVE-2026-54089 is a critical authentication bypass vulnerability in File Browser affecting instances configured with proxy-based authentication. An unauthenticated remote attacker with direct network access can impersonate arbitrary users or register new accounts by spoofing configured HTTP headers.
The malicious Cargo package 'exploration' was uploaded to the crates.io registry. During compilation or package import, the crate executes code designed to establish an outbound TCP/HTTP connection, download an external second-stage binary, and execute the binary locally on the host machine. This creates an unauthenticated remote code execution vector impacting developer environments and continuous integration pipelines.
CVE-2026-54088 is a critical command injection vulnerability in File Browser prior to version 2.63.6. When Hook Authentication is enabled, the application interpolates unsanitized credentials into a shell command, allowing unauthenticated remote code execution.
An authenticated remote code execution vulnerability exists in NotrinosERP (versions up to and including 1.0.0) within the Human Resource Management (HRM) module. Users with employee management permissions can upload arbitrary file types, including PHP scripts, which are written directly to a web-accessible directory. This allows for arbitrary code execution in the context of the web-server user.