Safeguard
Open Source

How to Secure webpack-dev-server Against Source Code Theft

webpack-dev-server is a local development server, not a production one, and two 2025 CVEs showed exactly why that distinction matters. Here is how it leaks and how to lock it down.

Priya Mehta
DevSecOps Engineer
5 min read

webpack-dev-server is a development-only tool, and treating it as anything more is where teams get burned. It rebuilds your bundle in memory, serves it over HTTP, and pushes hot updates to the browser over a WebSocket. That is a great inner-loop experience, but in 2025 two disclosed vulnerabilities proved that a carelessly exposed dev server can hand your unminified source code to any website you happen to visit while it is running.

If you install it from npm as webpack-dev-server, add it to devDependencies and never ship it. This post walks through what the recent CVEs actually do, why the fix landed in version 5.2.1, and the configuration habits that keep the webpack dev server contained to your machine.

What webpack-dev-server actually is

The webpack dev server watches your files, recompiles on change, and serves the output. It layers on Hot Module Replacement (HMR) so a saved edit patches the running page without a full reload. None of that is meant to leave localhost. There is no auth, no rate limiting, and the served bundle is the readable, source-mapped version of your app.

A minimal config looks like this:

// webpack.config.js
module.exports = {
  mode: 'development',
  devServer: {
    host: 'localhost',
    port: 8080,
    hot: true,
  },
};

The trouble starts when people change host to 0.0.0.0 to test from a phone on the same network, or when the default cross-origin behavior is looser than they assume.

CVE-2025-30359: source code theft via prototype pollution

CVE-2025-30359 is the more interesting of the two. The dev server did not properly validate cross-origin requests for JavaScript assets, specifically failing to check the Sec-Fetch-Mode and Sec-Fetch-Site headers browsers now send.

The attack goes like this: you visit a malicious page while your dev server is running on a known or guessable port. That page loads your bundle with a plain <script src="http://localhost:8080/main.js"> tag. Because scripts are executable rather than opaque cross-origin responses, the attacker's page can then use prototype pollution — overriding something like Array.prototype.forEach — to grab a reference to webpack's internal __webpack_modules__ object. From there, calling Function.prototype.toString() on each module function reconstructs your original source. It is fixed in webpack-dev-server 5.2.1.

CVE-2025-30360: WebSocket hijacking on non-Chromium browsers

The second issue, CVE-2025-30360, is a cross-site WebSocket hijacking flaw. The dev server's Origin validation was meant to block a malicious page from opening the HMR WebSocket, but it incorrectly accepted all IP-address origins. On non-Chromium browsers such as Firefox and Safari, an attacker page could connect to the HMR socket and, again, exfiltrate served code. Chromium-based browsers applied extra protections that blunted this path, but relying on your users' browser choice is not a control. This one is also resolved in 5.2.1.

Upgrade and verify

Both fixes shipped together, so the remediation is a single bump:

npm install --save-dev webpack-dev-server@^5.2.1
npm ls webpack-dev-server

Run npm ls to confirm a nested copy is not being pulled in by another tool such as an older Create React App or a Storybook version. If a transitive dependency pins an old range, an override forces the resolution:

{
  "overrides": {
    "webpack-dev-server": "^5.2.1"
  }
}

This is exactly the kind of transitive pin that hides in a lockfile. An SCA tool such as Safeguard can flag a vulnerable webpack-dev-server even when it is three levels deep in your dependency graph, which beats reading package-lock.json by hand. If you want the mechanics of that, our software composition analysis product page covers how transitive detection works.

Configuration habits that keep it contained

Upgrading closes the known holes, but the dev server should also be hard to reach in the first place.

  • Bind to localhost (or 127.0.0.1), not 0.0.0.0. If you must test on another device, use a reverse tunnel with auth instead of exposing the raw port.
  • Set an explicit allowedHosts list rather than the permissive 'all'.
  • Never run the dev server on a shared or public host, and never as part of a CI job that stays online.
module.exports = {
  devServer: {
    host: '127.0.0.1',
    port: 8080,
    allowedHosts: ['localhost'],
    client: { webSocketURL: 'ws://localhost:8080/ws' },
  },
};

Do not confuse it with a production server

The recurring root cause behind dev-server incidents is deploying it or leaving it running on an internet-facing box. Production builds should come from webpack --mode production and be served by a real static host or CDN, which serve minified, non-source-mapped assets and enforce their own headers. The webpack dev server has no place in that pipeline. Keeping it in devDependencies and out of your production image is a one-line policy your Dockerfile and CI can enforce.

FAQ

Is webpack-dev-server safe to use now?

Yes, on version 5.2.1 or later and bound to localhost. The 2025 CVEs are patched in that release. The remaining risk comes from misconfiguration, mainly exposing the port beyond your own machine.

Should webpack-dev-server ever be in production dependencies?

No. It belongs in devDependencies and should never be installed or run in a production environment. Serve production builds from a static host or CDN instead.

How do I check which version I have?

Run npm ls webpack-dev-server from your project root. It shows the resolved version and any nested copies pulled in by other tooling, so you can catch an old transitive one.

Does binding to localhost fully protect me?

It removes network exposure, which is the largest risk, but you should still stay current on patches. The CVE-2025-30359 attack targeted a bundle served on a local port, so patching plus localhost binding together give you defense in depth.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.