Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [18.x, 20.x, 22.x, 24.x]
node-version: [18.x, 20.x, 22.x, 24.x, 26.x]
shard: ["1/4", "2/4", "3/4", "4/4"]
webpack-version: [latest]

Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

### [5.2.4](https://github.com/webpack/webpack-dev-server/compare/v5.2.3...v5.2.4) (2026-05-11)

### Bug Fixes

* set Cross-Origin-Resource-Policy header to prevent source code theft over HTTP

### [5.2.3](https://github.com/webpack/webpack-dev-server/compare/v5.2.2...v5.2.3) (2026-01-12)


Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ Options:
-o, --output-path <value> The output directory as **absolute path** (required).
--stats [value] Stats options object or preset name.
--no-stats Negative 'stats' option.
-t, --target <value...> Environment to build for. Environment to build for. An array of environments to build for all of them when possible.
-t, --target <value...> Specific environment, runtime, or syntax. Environment to build for. An array of environments to build for all of them when possible.
--no-target Negative 'target' option.
--watch-options-stdin Stop watching when stdin stream has ended.
--no-watch-options-stdin Negative 'watch-options-stdin' option.
Expand Down
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module.exports = {
//
// FIXME: this uuid moduleNameMapper workaround can be removed after sockjs > uuid@v9 release
// https://github.com/uuidjs/uuid/pull/616#issuecomment-1206283882
// eslint-disable-next-line n/no-extraneous-require

"^uuid$": require.resolve("uuid"),
},
};
55 changes: 55 additions & 0 deletions lib/Server.js
Original file line number Diff line number Diff line change
Expand Up @@ -2019,6 +2019,14 @@ class Server {
return;
}

// Block cross-origin resource loading when Sec-Fetch-* headers are absent (HTTP origins)
if (
this.options.allowedHosts !== "all" &&
!this.isUserCORSWildcardEnabled()
) {
res.setHeader("Cross-Origin-Resource-Policy", "same-origin");
}

next();
},
});
Expand Down Expand Up @@ -3184,6 +3192,53 @@ class Server {
return false;
}

/**
* @private
* @returns {boolean} true when the user has configured a wildcard
* Access-Control-Allow-Origin header (opting into fully open cross-origin access)
*/
isUserCORSWildcardEnabled() {
const { headers } = this.options;

if (!headers) {
return false;
}

if (typeof headers === "function") {
return false;
}

/**
* @param {string | string[]} value header value
* @returns {boolean} true when value is the "*" wildcard
*/
const isWildcard = (value) => {
if (typeof value === "string") {
return value.trim() === "*";
}

if (Array.isArray(value)) {
return value.length === 1 && isWildcard(value[0]);
}

return false;
};

if (Array.isArray(headers)) {
return headers.some(
(header) =>
header.key.toLowerCase() === "access-control-allow-origin" &&
isWildcard(header.value),
);
}

return Object.entries(headers).some(
([key, value]) =>
key.toLowerCase() === "access-control-allow-origin" &&
isWildcard(value),
);
}

/**
* @private
* @param {{ [key: string]: string | undefined }} headers headers
Expand Down
Loading