CVE-2026-58039
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine. It offers an event-driven, non-blocking I/O model that makes it lightweight and efficient, and is widely used in server-side applications.
An improper access control vulnerability (CVE-2026-58039) has been identified in the Node.js Permission Model, the opt-in runtime sandbox that confines a process to an explicit filesystem allowlist. The permission check that guards diagnostic report writes was applied to the report file name before that name was joined with the configured report directory, so code running inside the sandbox can use process.report to write, and to overwrite, files outside the paths granted by --allow-fs-write.
Per MITRE, CWE-284 (Improper Access Control) describes a product that "does not restrict or incorrectly restricts access to a resource from an unauthorized actor," which allows attackers to access functionality or data the access control was meant to keep out of reach.
This issue affects Node.js 22.x up to and including 22.23.1, 24.x up to and including 24.18.0, and 26.x up to and including 26.5.0, together with all versions of the End-of-Life 20.x line. It is only reachable when the process is started with the Permission Model enabled (--experimental-permission on Node.js 20, --permission on Node.js 22 and later).
Details
Module Info
- Product: Node.js
- Affected packages: nodejs/node (the Node.js runtime itself)
- Affected versions:
- 22.x ≤ 22.23.1
- 24.x ≤ 24.18.0
- 26.x ≤ 26.5.0
- 20.x (EOL, all versions)
- GitHub repository: https://github.com/nodejs/node
- Published packages: https://github.com/nodejs/node/releases
- Package manager: N/A (ships as a runtime distribution)
- Fixed in: NES for Node.js v20.20.4
Vulnerability Info
This Low-severity vulnerability is found in the permission subsystem of the Node.js runtime itself, in every affected release line, and is only reachable when the process is started with the Permission Model enabled. Applications that do not enable the Permission Model have no allowlist to bypass and are not affected.
The Permission Model was introduced in Node.js 20 and restricts what the process may touch on disk. Paths passed to --allow-fs-read and --allow-fs-write form the allowlist, and every filesystem operation the runtime performs is expected to be checked against it. A diagnostic report is one such operation: process.report.writeReport() serializes a JSON summary of the process, including stack traces, heap and resource statistics, and by default the process environment variables, to a file whose location is built from process.report.directory and the file name passed to the call.
The permission check ran too early. The runtime validated the file name on its own and only afterwards joined it with the report directory, so the path that was checked was not the path that was written. Code inside the sandbox could set process.report.directory to a location outside the allowlist and call writeReport() with a plain relative file name: the check passed against the bare name, and the report was then written to the composed path. The result is a file created or overwritten outside the granted paths, with report contents that may include environment variables landing where the sandbox was meant to prevent writes. The upstream fix composes the final output path first and then runs the write permission check against it, in both the JavaScript entry point (lib/internal/process/report.js) and the native report writer (src/node_report.cc).
Note: Node.js 18 and earlier are not affected. The Permission Model was introduced in Node.js 20, so the earlier End-of-Life lines have no --allow-fs-write boundary for this flaw to cross.
Steps To Reproduce
The steps below follow the regression test added by the upstream fix (test/parallel/test-permission-fs-write-report.js).
- Start the application with the Permission Model enabled, granting write access only to an allowed directory. On Node.js 20 the flag is --experimental-permission; on Node.js 22 and later it is --permission.
node --experimental-permission \
--allow-fs-read=* \
--allow-fs-write=/tmp/allowed \
app.js- From inside the application, point the report directory at a path outside the allowlist and write a report under a plain relative file name.
process.report.directory = '/tmp/denied';
process.report.writeReport('report.json');- On an affected runtime the call succeeds and /tmp/denied/report.json is created, or overwritten if it already exists, even though /tmp/denied was never granted. On a patched runtime the composed path is checked and the call is refused.
Error: Access to this API has been restricted
code: 'ERR_ACCESS_DENIED',
permission: 'FileSystemWrite',
resource: '/tmp/denied/report.json'Mitigation
The Node.js 20 release line reached End-of-Life on March 24, 2026 and will not receive an upstream fix for this issue. For more information see here.
Users of the affected components should apply one of the following mitigations:
- Upgrade to a supported Node.js release that carries the fix: 22.23.2, 24.18.1, or 26.5.1 or later.
- Migrate affected applications off the End-of-Life Node.js 20 line.
- Leverage a commercial support partner like HeroDevs for post-EOL security support (NES for Node.js).
Credits
- sinan-polat (reporter)
- RafaelGSS (remediation developer)