Like someone being able to knock on your workshop door and make your desk lamp flick on, but they can't see what's on your desk
CVE-2026-14620 is a cross-site request forgery in webpack-dev-server ≤ 5.2.5 that lets a malicious website a developer visits silently fire GET requests to two internal endpoints on localhost: /webpack-dev-server/open-editor?fileName=<path> and /webpack-dev-server/invalidate. The existing guard only blocked no-cors sub-resource requests but failed to catch navigation-mode requests (via iframe/window.open) and explicit CORS fetch calls ({mode:'cors'}). This means a drive-by page can invoke launchEditor() with an attacker-chosen file path — including paths outside the project root like ~/.ssh/config — spawning editor processes on the developer's machine. Repeated calls to /invalidate can force recompilations, degrading local build performance. Affected versions span all webpack-dev-server releases through 5.2.5; the fix shipped in 5.2.6 (PR #5698). The vulnerability also carries CWE-749 (Exposed Dangerous Method). All 4.x versions are affected as well, since the endpoints exist in that branch without origin checks.
The vendor rated this MEDIUM (4.7) and frankly that's generous even by its own CVSS vector (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:N/A:L), which scores only a Low availability impact with zero confidentiality and zero integrity impact. The 'Changed scope' bump in the vector refers to the fact that the cross-origin page triggers actions in a different security domain (the dev server), but the real-world consequence is: some files open in your editor, and your laptop fans spin harder from forced recompilations. There is no data exfiltration path — the attacker triggers a local side-effect but receives no response data. For an enterprise managing 10,000 hosts, this vulnerability exists exclusively on developer workstations during active development. It cannot affect production servers, domain controllers, CI/CD runners (which don't browse the web), or any infrastructure tier. The vendor's MEDIUM is appropriate for an individual developer's risk but overstates the enterprise priority.
4 steps from start to impact.
Developer runs webpack-dev-server locally
webpack-dev-server (typically on localhost:8080 or another configured port) during active front-end development. The server binds to localhost by default. The open-editor and invalidate endpoints are enabled unconditionally in all versions ≤ 5.2.5 — there is no opt-out configuration.- Developer workstation has webpack-dev-server ≤ 5.2.5 installed as a devDependency
- Developer actively running the dev server during a coding session
- Only active during development sessions — the server is not a persistent service
- Does not run on production servers, CI/CD agents, or any non-developer hosts
Developer visits attacker-controlled page
http://localhost:8080/webpack-dev-server/open-editor. This requires user interaction: the developer must actively browse to the page. No phishing email click-through or credential entry is needed — just visiting the page is sufficient.- Developer must be browsing the web during an active dev-server session
- Attacker must know or guess the dev-server port (default 8080)
- The timing window requires the developer to be both running the dev server AND visiting the malicious page simultaneously
- Non-default ports reduce guessability, though attackers can spray common ports
Cross-origin request triggers launchEditor()
<iframe> or window.open() targeting the endpoint URL (navigation-mode, sec-fetch-mode: navigate), or (B) a fetch() call with {mode:'cors'}. The dev server's guard only checked for no-cors subresource requests and missed both vectors. The GET request reaches launchEditor(fileName) with an attacker-supplied fileName parameter. The ExploitDB PoC (EDB-52649) by researcher Pig-Tail (Jorge González Milla) demonstrates all three vectors.- Dev server ≤ 5.2.5 with the flawed origin guard
- Browser must be the same browser session where the dev server page is open (same-machine)
- Corporate web proxies and DNS-based security tools may block or flag cross-origin requests to localhost/127.0.0.1
- Browsers are increasingly restricting private network access (Chrome's Private Network Access spec) which may block this in future versions
Local side-effect: editor spawns or recompilation forced
launchEditor() function spawns the developer's configured editor (VS Code, vim, etc.) with the attacker-chosen file path. This can open files outside the project root (e.g., ~/.ssh/config, /etc/passwd). The /invalidate endpoint forces a webpack recompilation. Crucially, no response data is returned to the attacker — the Same-Origin Policy prevents the malicious page from reading any response. The impact is purely local: unwanted editor windows and CPU load from recompilations.- A valid, existing file path must be guessed or known by the attacker (non-existent paths fail silently)
- The attacker gains zero data exfiltration — this is a blind fire-and-forget side-effect
- Opening a file in an editor is visible to the developer immediately, likely prompting investigation
- No persistent foothold, no privilege escalation, no lateral movement capability
npm audit fix or npm install webpack-dev-server@latest across all repositories. Since this is a devDependency, the change has zero production deployment risk — it only affects local dev environments. As a LOW-severity item, there is no noisgate mitigation SLA; proceed directly to the remediation window. Include in your next scheduled dependency update cycle.devServer.port to a non-standard value in webpack.config.js. This forces attackers to guess the port, adding friction to the blind CSRF. Not a fix — the endpoint remains unprotected — but reduces the probability of successful exploitation. This is a low-effort config change developers can make immediately.InsecurePrivateNetworkRequestsAllowed enterprise policy set to false, or use browser extensions that block cross-origin requests to localhost (e.g., uBlock Origin rules). This breaks the attack at the browser layer regardless of dev-server version.- WAF / reverse proxy rules — the dev server runs on localhost; enterprise WAFs and proxies sit on the network perimeter and never see traffic to 127.0.0.1. No WAF rule can intercept this attack path.
- Network segmentation / firewall rules — the attack originates from the developer's own browser making a request to their own localhost. No network boundary is crossed. VLANs, micro-segmentation, and firewall ACLs are irrelevant.
- npm audit --production — this flag excludes devDependencies from the audit, so the vulnerable webpack-dev-server won't appear in production audit reports. Teams must run
npm auditwithout--productionor use--include=devto catch this.
The supporting signals.
| In-the-Wild Exploitation | None observed. Not listed in CISA KEV. No reports of active exploitation campaigns. No GreyNoise or Shodan scan activity — the vulnerable endpoint is on localhost, making internet-scale scanning irrelevant. |
|---|---|
| Proof of Concept | Public. ExploitDB EDB-52649 published 2026-07-17 by Pig-Tail (Jorge González Milla). Full PoC repo at github.com/Pig-Tail/security-research. Demonstrates navigation, CORS fetch, and no-cors vectors with sentinel editor validation. |
| EPSS | 0.00521 (0.52%) — bottom quartile. Reflects the dev-only attack surface and limited impact. |
| KEV Status | Not listed. No federal agency remediation deadline applies. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:N/A:L — Network-adjacent via browser, requires user interaction, changed scope (cross-origin trigger), zero C/I impact, low availability. The 4.7 score is almost entirely from the scope change and attack accessibility; the actual damage metrics are minimal. |
| Affected Versions | webpack-dev-server ≤ 5.2.5 (all 5.x releases) and all 4.x releases. The vulnerable endpoints exist without origin validation in both major version branches. |
| Fixed Version | 5.2.6 (PR #5698). No backport to 4.x has been announced. Migration to 5.x is recommended for 4.x users. |
| Install Base | ~16–18 million weekly npm downloads. However, this is a devDependency — it runs exclusively on developer machines during active development, not in production deployments. Roughly 0% of production hosts in a typical enterprise are affected. |
| Disclosure Date | 2026-07-03 (advisory published). ExploitDB PoC published 2026-07-17. |
| Reporter | Pig-Tail (Jorge González Milla). Coordinated with webpack maintainers bjohansebas and UlisesGascon via GitHub Security Advisory GHSA-f5vj-f2hx-8m93. |
Sources.
- GitHub Security Advisory GHSA-f5vj-f2hx-8m93
- ExploitDB EDB-52649 — webpack_devserver 5.2.5 CSRF PoC
- Pig-Tail Security Research — CVE-2026-14620 write-up and PoC
- OpenCVE — CVE-2026-14620 Detail
- webpack-dev-server npm package
- CyberStrike — CVE-2026-14620 Detail
- Snyk — webpack-dev-server Vulnerability Database
Why this verdict
- Dev-only attack surface: webpack-dev-server is a
devDependencythat runs exclusively on developer workstations during active coding sessions. It is never deployed to production servers, infrastructure tiers, or any host in a fleet that a patch-management engine typically prioritizes. In a 10,000-host enterprise, perhaps 200–500 developer machines have it installed, and it's only *running* during active front-end development — a fraction of the workday. - Zero data exfiltration: The CVSS vector explicitly scores C:N/I:N — the attacker triggers a local side-effect (editor opens, recompilation fires) but the Same-Origin Policy prevents any response data from reaching the attacker. This is a blind fire-and-forget: no credentials stolen, no source code exfiltrated, no reverse shell, no persistence.
- User interaction required with narrow timing window: The developer must be simultaneously running the dev server AND visiting a malicious page. This is not a wormable or scan-and-exploit vulnerability. The EPSS of 0.52% reflects this narrow attack window.
- Role multiplier: webpack-dev-server occupies exclusively low-value roles — developer workstations and sandboxes (category a). It does not run on CI/CD agents (which don't browse the web, so the CSRF vector is moot even if installed), production servers, domain controllers, identity providers, hypervisors, or any high-value infrastructure tier. The blast radius on successful exploitation is: one developer's local machine experiences unwanted editor spawns and CPU load. No domain-scale, fleet-scale, or supply-chain impact is plausible. No high-value role floor applies.
- Browser mitigations trending toward closure: Chrome's Private Network Access (PNA) specification is progressively restricting cross-origin requests from public websites to localhost/private IPs. While not fully enforced in all browsers today, this will further attenuate the attack surface over time.
Why not higher?
The vendor's MEDIUM (4.7) accounts for the cross-origin scope change and the ease of triggering the request, which is fair in isolation. But for enterprise patch prioritization, the vulnerability affects zero production hosts, provides zero data to the attacker, and requires a narrow coincidence of developer behavior. There is no high-value role deployment scenario that would floor this at MEDIUM or above — webpack-dev-server is definitionally a developer sandbox tool.
Why not lower?
Despite the minimal blast radius, a public PoC exists on ExploitDB with trivial weaponization (just an HTML page), the npm install base is massive (16M+ weekly downloads ensuring many developers have it), and the local side-effects — while not exfiltration — could be chained by a creative attacker as a nuisance vector or used in targeted attacks against specific developers to draw attention to sensitive file paths. This warrants tracking as LOW rather than IGNORE.
Crowdsourced verification payload.
Run this script on any developer workstation where Node.js projects may use webpack-dev-server. It checks all node_modules directories under a given project root. No special privileges needed — run as the developer user. Example: bash check_cve_2026_14620.sh /home/dev/projects
#!/usr/bin/env bash
# check_cve_2026_14620.sh — Detect webpack-dev-server <= 5.2.5 (CVE-2026-14620)
# Usage: bash check_cve_2026_14620.sh <project_root>
# Exit codes: 0 = PATCHED/not present, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
SEARCH_ROOT="${1:-.}"
VULN_FOUND=0
if ! command -v node &>/dev/null; then
echo "UNKNOWN — node not found on PATH; cannot check package versions"
exit 2
fi
# Find all installed webpack-dev-server instances
while IFS= read -r -d '' pkg_json; do
dir="$(dirname "$pkg_json")"
name=$(node -e "try{console.log(require('$pkg_json').name||'')}catch(e){console.log('')}" 2>/dev/null)
version=$(node -e "try{console.log(require('$pkg_json').version||'')}catch(e){console.log('')}" 2>/dev/null)
if [[ "$name" != "webpack-dev-server" ]] || [[ -z "$version" ]]; then
continue
fi
# Compare version: vulnerable if <= 5.2.5
major=$(echo "$version" | cut -d. -f1)
minor=$(echo "$version" | cut -d. -f2)
patch=$(echo "$version" | cut -d. -f3 | cut -d- -f1)
if [[ "$major" -lt 5 ]]; then
echo "VULNERABLE — $dir: webpack-dev-server@$version (all 4.x affected)"
VULN_FOUND=1
elif [[ "$major" -eq 5 ]]; then
if [[ "$minor" -lt 2 ]]; then
echo "VULNERABLE — $dir: webpack-dev-server@$version"
VULN_FOUND=1
elif [[ "$minor" -eq 2 && "$patch" -le 5 ]]; then
echo "VULNERABLE — $dir: webpack-dev-server@$version"
VULN_FOUND=1
else
echo "PATCHED — $dir: webpack-dev-server@$version (>= 5.2.6)"
fi
else
echo "PATCHED — $dir: webpack-dev-server@$version (>= 6.x)"
fi
done < <(find "$SEARCH_ROOT" -path '*/node_modules/webpack-dev-server/package.json' -print0 2>/dev/null)
if [[ "$VULN_FOUND" -eq 1 ]]; then
echo ""
echo "VULNERABLE — one or more webpack-dev-server installations <= 5.2.5 found"
exit 1
else
echo ""
echo "PATCHED — no vulnerable webpack-dev-server installations found (or not installed)"
exit 0
fi