Upgrading webpack-dev-server 4 to 5
Review needed4.15.2 → 5.2.7Security13New5Changed1Fixed23
SecurityValidates Host and Origin headers and enforces same-origin checks on WebSocket upgrade requests handled by proxies with ws: true.#5766 ↗
Review neededUpgrade verdict
1 changed default and 11 security fixes.
In plain terms
- Stops other websites from opening a WebSocket connection to services proxied through the dev server.
- Host checks now apply even when allowedHosts is set to "all", and bad open-editor links get a controlled error instead of relying on the Host header.
- webpack-dev-server vulnerable to cross-site request forgery via internal developer endpoints
- webpack-dev-server vulnerable to denial of service via a malformed Host or Origin header
Must act Top 3 of 11 that need code or config changes
webpack-dev-server publishes an official migration guide for version 5. It covers more than the release notes do.
Migration Guide and Changes ↗Node.js requirement changed in 5.0.0: >= 12.13.0 → >= 18.12.0.
Adds @types/express-serve-static-core ^4.17.21.
Drops default-gateway, html-entities, rimraf.
Installs 241 packages in all (was 217).
What you must change
Security11
Validates Host and Origin headers and enforces same-origin checks on WebSocket upgrade requests handled by proxies with ws: true.
HostOriginwsValidates Host and HTTP/2 authority headers independently of Origin protocol exceptions, including when allowedHosts is "all", and handles malformed open-editor URLs.
HostallowedHostswebpack-dev-server vulnerable to cross-site request forgery via internal developer endpoints
/webpack-dev-server/invalidate/webpack-dev-server/open-editorSec-Fetch-SiteOriginHostModerate · CVSS 4.7webpack-dev-server vulnerable to denial of service via a malformed Host or Origin header
Moderate · CVSS 5.3webpack-dev-server vulnerable to HMR WebSocket interception via permissive user proxies
Moderate · CVSS 5.3webpack-dev-server vulnerable to cross-origin source code exposure on non-HTTPS origins
Cross-Origin-Resource-PolicyModerate · CVSS 5.3Cross-origin requests are not allowed unless permitted by the Access-Control-Allow-Origin header.
Access-Control-Allow-OriginRequests with an IP address in the Origin header cannot connect to the WebSocket server unless allowed by allowedHosts or differing from the Host header.
OriginallowedHostsHostwebpack-dev-server users' source code may be stolen when they access a malicious web site with non-Chromium based browser
Moderate · CVSS 6.5webpack-dev-server users' source code may be stolen when they access a malicious web site
Moderate · CVSS 5.3Bumps webpack-dev-middleware to address a security issue.
webpack-dev-middlewareAPI changes
Generated by DepDelta from published .d.ts files. Not mixed with prose notes.
- changed:
const _exports: { 'allowed-hosts': { configs: (| { type: string; multiple: boolean; description: string; path: string } | { description: string; multiple: boolean; path: strin… → const _exports: { 'allowed-hosts': { configs: (| { type: string; multiple: boolean; description: string; path: string; values?: undefined } | { description: string; multiple:…
- removed:
export = processArguments - removed:
function processArguments(args: Record<string, Argument>, config: any, values: Record<string, string | number | boolean | RegExp | (string | number | boolean | RegExp)[]>): Problem[] | null - removed:
namespace processArguments
- changed:
type CliOption = { name: string; package: string; binName: string; installed: boolean; url: string; preprocess: Function } → type CliOption = { name: string; package: string; binName: string; installed: boolean; url: string; preprocess: () => void }
- removed:
method Server.close(callback?: ((err?: Error) => void) | undefined): void - removed:
method Server.listen(port: Port, hostname: Host, fn: (err?: Error) => void): void - removed:
static get Server.cli(): { readonly getArguments: () => { 'allowed-hosts': { configs: (| { type: string; multiple: boolean; description: string; path: string } | { description: string; multiple: boolean; path: string; type: string; values: string[] })[]; description: string; multiple: boolean; simpleType: string }; 'allowed-hosts-reset': { configs: { type: string; multiple: boolean; description:… - changed:
class Server → class Server<A extends BasicApplication = import('express').Application, S extends BasicServer = import('http').Server<typeof import('http').IncomingMessage, typeof import('http').ServerResponse>> - changed:
constructor Server(options: | import('webpack').Compiler | import('webpack').MultiCompiler | Configuration | undefined, compiler: Compiler | MultiCompiler | Configuration) → constructor Server(options: Configuration<A, S> | undefined, compiler: Compiler | MultiCompiler) - changed:
method Server.sendMessage(clients: ClientConnection[], type: string, data?: any, params?: any): void → method Server.sendMessage(clients: ClientConnection[], type: string, data?: EXPECTED_ANY | undefined, params?: EXPECTED_ANY | undefined): void - changed:
method Server.watchFiles(watchPath: string | string[], watchOptions?: import('chokidar').WatchOptions | undefined): void → method Server.watchFiles(watchPath: string | string[], watchOptions?: WatchOptions | undefined): void - changed:
property Server.app: import('express').Application | undefined → property Server.app: A | undefined - changed:
property Server.middleware: | import('webpack-dev-middleware').API<import('express').Request<import('express-serve-static-core').ParamsDictionary, any, any, qs.ParsedQs, Record<string, any>>, import('express').Response<any, Record<string, any>>> | null | undefined → property Server.middleware: | import('webpack-dev-middleware').API<import('express').Request<import('express-serve-static-core').ParamsDictionary, any, any, qs.ParsedQs, Record<string, any>>, import('express').Response<any, Record<string, any>>> | undefined - changed:
property Server.options: Configuration → property Server.options: Configuration<A, S> - changed:
property Server.server: import('http').Server | undefined | null → property Server.server: S | undefined - changed:
static get Server.schema(): { title: string; type: string; definitions: { AllowedHosts: { anyOf: (| { type: string; minItems: number; items: { $ref: string }; enum?: undefined; $ref?: undefined } | { enum: string[]; type?: undefined; minItems?: undefined; items?: undefined; $ref?: undefined } | { $ref: string; type?: undefined; minItems?: undefined; items?: undefined; enum?: undefined })[]; descr… → static get Server.schema(): { title: string; type: string; definitions: { App: { instanceof: string; description: string; link: string }; AllowedHosts: { anyOf: (| { type: string; minItems: number; items: { $ref: string }; enum?: undefined; $ref?: undefined } | { enum: string[]; type?: undefined; minItems?: undefined; items?: undefined; $ref?: undefined } | { $ref: string; type?: undefined; minIt… - changed:
static method Server.findIp(gateway: string): string | undefined → static method Server.findIp(gatewayOrFamily: string, isInternal?: boolean | undefined): string | undefined - added:
method Server.getClientEntry(): string - added:
method Server.getClientHotEntry(): string | void - added:
property Server.isTlsServer: boolean | undefined