CVE-2026-56847
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 uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, and it is widely used in server-side applications.
A permission model bypass (CVE-2026-56847) has been identified in Node.js, which allows trace logs to be written outside the paths granted by --allow-fs-write. Code running under the Node.js Permission Model can call trace_events.createTracing().enable() and cause the runtime to create a trace log file at a path the allowlist does not cover.
Per MITRE, missing authorization occurs when "the product does not perform an authorization check when an actor attempts to access a resource or perform an action." Here the Permission Model performs that check on ordinary filesystem writes but not on the write the tracing agent performs, so a path the operator deliberately excluded from the allowlist can still be written to.
This issue affects only Node.js releases that carry the Permission Model, which was introduced in Node.js 20, and only processes started with the --permission flag. Node.js 18.x and earlier do not implement the Permission Model and are not affected.
Details
Module Info
- Product: Node.js
- Affected packages: nodejs/node (the runtime itself)
- Affected versions:
- 22.x ≤ 22.23.1
- 24.x ≤ 24.18.0
- 26.x ≤ 26.5.0
- 20.x (EOL, all)
- GitHub repository: https://github.com/nodejs/node
- Published packages: https://github.com/nodejs/node/releases
- Package manager: n/a (Node.js ships as a runtime distribution, not as a registry package)
- Fixed in: NES for Node.js v20.20.4
Vulnerability Info
This Low-severity vulnerability is found in the trace events subsystem of the nodejs/node runtime and is only reachable when the process is started with the --permission flag.
The Node.js Permission Model lets an operator run semi-trusted code with an explicit filesystem allowlist rather than the ambient authority of the process user. --allow-fs-read and --allow-fs-write name the paths the process may read and write, and every filesystem operation is expected to be checked against those grants before it runs. Separately, the trace_events module records V8 and Node.js runtime diagnostics, writing them to a trace log file (by default node_trace.<rotation>.log in the process working directory) once a tracing object is enabled.
The two features did not meet. NodeCategorySet::Enable() started the tracing agent without asking the Permission Model whether the destination path was writable, so the trace writer created its log file relative to the working directory regardless of what --allow-fs-write granted. A caller confined to an allowlist could therefore place a file outside it, and the trace log itself carries runtime diagnostics that the operator did not intend to expose at that location. The write is limited to the tracing agent’s own log file, so this is a boundary bypass rather than arbitrary file write.
The upstream fix (commit 3cb607dfc4) adds a THROW_IF_INSUFFICIENT_PERMISSIONS check for PermissionScope::kFileSystemWrite in src/node_trace_events.cc, so enabling a tracing object now throws ERR_ACCESS_DENIED when the trace file path falls outside the allowlist. It shipped in Node.js 22.23.2, 24.18.1 and 26.5.1 in the July 29, 2026 Node.js security release. The GitHub Security Advisory for this issue is GHSA-hw7r-7v27-7388.
Note: The Permission Model is opt-in. Applications that do not start with --permission enforce no filesystem allowlist at all, so there is no boundary for this issue to cross.
Steps To Reproduce
The following steps come from the test case added with the upstream fix, test/parallel/test-permission-fs-write-trace-events.js.
- Create two directories, one that will be granted write access and one that will not, and make the ungranted directory the working directory of the process.
mkdir -p /tmp/allowed /tmp/outside
cd /tmp/outside- Start Node.js with the Permission Model enabled, granting write access only to /tmp/allowed.
node --permission --allow-fs-read=* --allow-fs-write=/tmp/allowed repro.js- Confirm the allowlist is being enforced for ordinary writes. This throws on both affected and patched versions.
const fs = require('fs');
try {
fs.writeFileSync('canary', 'x');
} catch (err) {
console.log(err.code); // ERR_ACCESS_DENIED, permission 'FileSystemWrite'
}- Enable a tracing object from the same process.
const tracing = require('trace_events').createTracing({
categories: ['node', 'v8', 'node.perf'],
});
tracing.enable();- Check the working directory. On affected versions tracing.enable() succeeds and node_trace.1.log is created in /tmp/outside, which was never granted write access. On patched versions the call throws ERR_ACCESS_DENIED naming node_trace.1.log as the resource, and no file is created.
ls /tmp/outside
# affected: node_trace.1.log
# patched: (empty)Mitigation
Node.js 20 is past its end-of-life date 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 patched supported release: Node.js 22.23.2, 24.18.1 or 26.5.1.
- Migrate affected applications away from end-of-life Node.js 20.
- Leverage a commercial support partner like HeroDevs for post-EOL security support.
Credits
- 0xoroot (reporter)
- RafaelGSS from the Node.js project (remediation developer)