CVE-2026-58043: Node.js Permission Model Filesystem Allowlist Bypass
How a radix tree split node in the Node.js Permission Model grants read and write access to files that were never on the allowlist

Node.js disclosed CVE-2026-58043 on July 29, 2026, a High-severity filesystem allowlist bypass in the Permission Model, reported by researcher sy2n0 through HackerOne. HackerOne, the CNA, scores it 7.5 (CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N). The flaw (CWE-284, Improper Access Control) lives in the radix tree that backs --allow-fs-read and --allow-fs-write. When inserting a new path forces an existing node to split, the shared prefix node was itself marked as a granted endpoint, so code running under --permission can read and write paths that were never allowlisted. Node.js 22.23.1, 24.18.0, 26.5.0 and earlier are affected. Fixes shipped in 22.23.2, 24.18.1, and 26.5.1. Node.js 18 and 20 are end-of-life with no OSS fix available.
Affected and unsupported? See NES for Node.js.
What is CVE-2026-58043?
CVE-2026-58043 is an improper access control flaw (CWE-284) in the Node.js Permission Model, the runtime sandbox enabled with the --permission flag. The Permission Model is the feature that lets you run untrusted or semi-trusted code, including third-party dependencies, with an explicit filesystem allowlist instead of the ambient authority of the process user.
The affected component is the radix tree in src/permission/fs_permission.h that stores the allowlist and answers every filesystem permission check. Paths passed to --allow-fs-read and --allow-fs-write are inserted into this tree character by character, and each granted path terminates in a node flagged as an end node. A permission check walks the tree against the requested path and succeeds if it lands on an end node or a wildcard child.
The bug is in how the tree handles a node split. When a newly inserted path diverges partway through an existing node's stored prefix, that node is split into a shared parent segment and a child segment. The insert logic set the end node flag on the split boundary unconditionally, which promoted the shared character prefix into a grant of its own. Because the tree matches on character prefixes rather than on path segments, that promoted prefix covers every path that starts with those characters, including sibling files and directories that were never on the allowlist.
Upstream fixed it in commit ad99d075b1, titled "permission: avoid granting radix split nodes."
Severity and exploit conditions
HackerOne, as the assigning CNA, published a CVSS v3.0 base score of 7.5 (High). NVD had not completed its own analysis at the time of writing, so the CNA score is the authoritative figure. CISA's SSVC assessment records exploitation as "none," automatable as "no," and technical impact as "total."
Exploit prerequisites, in order:
- The application runs with the Permission Model enabled (--permission on Node.js 22.13.0 and later, 24.x, and 26.x; --experimental-permission on earlier releases).
- The allowlist contains at least two paths that share a character prefix, which is what causes the radix tree to split a node. Granting several sibling files inside the same directory is the common shape.
- Attacker-controlled code executes inside that process. A malicious transitive dependency, an untrusted plugin, or a compromised build step all satisfy this.
- A sensitive path exists whose name begins with the shared prefix.
The AC:H rating is doing real work here. The attacker does not choose the allowlist, so whether a useful path falls inside the over-granted prefix depends on the operator's configuration. Where an application grants many similarly named files, the odds move in the attacker's favor.
Exploitation status
There is no public proof of concept for CVE-2026-58043 as of this writing, and no report of exploitation in the wild. CISA's SSVC vector published alongside the CVE records exploitation as "none," and the CVE does not appear in the CISA Known Exploited Vulnerabilities catalog.
What is public is the upstream regression test that shipped with the fix. The test added to test-permission-fs-read.js grants read access to three files named secret1, secret2, and secret3, then asserts that a separate file named secret in the same directory remains unreadable. Before the fix, inserting those three paths split the radix tree at the shared prefix secret and marked that boundary as a grant, so the unlisted secret file was readable. That test is the clearest public description of the boundary condition and it requires no weaponized payload to understand.
Root cause: a split node that inherits a grant it never had
The Permission Model stores allowlisted paths in a radix tree so that permission checks stay cheap. Two behaviors combine to produce the bypass.
First, directory grants are encoded as wildcards. The Node.js documentation states that "when the permission model is initialized, it will automatically add a wildcard () if the specified directory exists," and that "after passing a wildcard character () all subsequent characters will be ignored." Matching therefore happens against a character prefix, not against a sequence of path segments. Nothing in the lookup requires that the next character after a matched prefix be a path separator.
Second, inserting a path that diverges partway through an existing node's prefix forces a split. The tree creates a new intermediate node holding the shared segment and reattaches the original node beneath it. The pre-fix insert path set child->is_leaf = true unconditionally at that boundary, so the intermediate node produced by the split was treated as a terminated, granted path. It never was one. It is a structural artifact of how the tree stores strings.
The fix captures the node's prior state before the split with a child_was_end_node flag derived from IsEndNode(), and only restores the end node marker if the original child genuinely was one. The same commit corrects the split position comparison from i > prefix_len to i >= prefix_len so the split happens at the right character.
The lesson generalizes past Node.js. Any access control layer that stores paths as strings and matches on prefixes has to decide, explicitly, that a match ends at a separator. Structure-sharing optimizations such as radix trees create internal nodes that look like valid termination points, and if the data structure's internal bookkeeping is allowed to leak into the authorization decision, the optimization becomes the vulnerability.
What an attacker can do
Code running inside a --permission sandbox that hits this flaw can:
- Read credential and configuration files that share a name prefix with an allowlisted file. An allowlist covering /var/run/secrets/token-a and /var/run/secrets/token-b splits at /var/run/secrets/token and exposes a distinct /var/run/secrets/token file that was deliberately withheld.
- Read application secrets adjacent to granted config. Granting /app/config.json and /app/config.yaml splits at /app/config, which can reach files such as /app/config or other entries beginning with that string.
- Write to paths outside the intended write allowlist when --allow-fs-write grants share a prefix, which puts files the application later reads, requires, or executes within reach of attacker-controlled content.
- Defeat the specific control an operator deployed to contain an untrusted dependency. The Permission Model is most often enabled precisely because the operator does not trust everything in node_modules, so a bypass returns exactly the capability the sandbox was meant to remove.
The practical impact scales with how granular the allowlist is. Configurations that enumerate many individual sibling files create more split nodes, and therefore more over-granted prefixes, than configurations that grant a directory outright.
Who is affected?
CVE-2026-58043 affects Node.js 22.x, 24.x, and 26.x per the upstream advisory. Applications that never enable the Permission Model are not exposed by this flaw, since the radix tree is only consulted when --permission is active.
Node.js 18 and 20 receive no upstream security analysis at all, which is the larger issue for teams still on those lines. The July 2026 batch carried eleven CVEs, and EOL lines were evaluated by nobody upstream.
Mitigation guidance
Defense in depth while you schedule the upgrade:
- Prefer directory grants over enumerated sibling files. Granting --allow-fs-read=/app/config/ creates one wildcard subtree. Granting /app/config/a.json, /app/config/b.json, and /app/config/c.json creates the split nodes this flaw exploits.
- Audit allowlists for shared prefixes. Review every --allow-fs-read and --allow-fs-write value for pairs that share a leading string, then check whether any sensitive file's path begins with that string.
- Move sensitive files out of prefix range. Renaming secret to private-secret removes it from the over-granted prefix. This is a stopgap, not a fix.
- Enforce at the operating system layer. Read only root filesystems, tmpfs mounts for writable paths, non root users, and a Kubernetes securityContext with readOnlyRootFilesystem: true all constrain the process regardless of what the in-process check decides.
- Keep secrets out of the process filesystem. Injected environment variables or a secrets manager fetch removes the file the bypass would otherwise reach.
- Verify grants at runtime. process.permission.has('fs.read', path) lets you assert at startup that paths you expect to be denied actually are.
Note the standing upstream caveat that is not part of this CVE but compounds it. The Node.js documentation warns that "symbolic links will be followed even to locations outside of the set of paths that access has been granted to." An allowlisted directory containing an attacker-writable symlink is its own exposure.
Related CVEs
CVE-2026-58043 was one of three Permission Model flaws in the same July 29, 2026 release, and one of eleven CVEs overall:
- CVE-2026-56847 (Low): Permission Model trace events write outside the allowlist. Fixed in 22.23.2, 24.18.1, and 26.5.1.
- CVE-2026-58039 (Low): Permission Model process reports write outside the allowlist. Fixed in 22.23.2, 24.18.1, and 26.5.1.
- CVE-2026-56846 and CVE-2026-56848 (High): HTTP/2 memory limit bypass and a re-entrant send use after free.
Our full breakdown of the batch is in Node.js July 2026 Security Release: 11 CVEs, Node 18 and 20 EOL. For the pattern across the year, see the June 2026 security releases and the March 2026 release covering eight CVEs. Other Node.js CVE deep dives worth reading alongside this one: CVE-2026-21717, the HashDoS vulnerability in V8, and CVE-2025-23087, the first universal CVE for Node.js.
Taking action
If you run Node.js 22.x, 24.x, or 26.x with the Permission Model enabled, upgrade to 22.23.2, 24.18.1, or 26.5.1. The change is a patch release on each line, and it is the complete fix.
If you are on Node.js 18 or 20, the calculus is different. Both lines are past end-of-life, so no upstream OSS fix exists for this or for the other ten CVEs in the July 2026 batch, and no upstream maintainer is assessing EOL lines against new disclosures at all. That gap widens with every release cycle. NES for Node.js provides drop-in replacement builds for EOL Node.js lines so you can resolve vulnerabilities on your current runtime while you plan a migration on your own schedule. HeroDevs partners officially with the Node.js project to deliver that support.
Either way, adjust the assumption underneath the deployment. Three Permission Model bypasses in a single release, on top of the flaws found earlier in 2026, say the sandbox is a hardening layer rather than a trust boundary. Pair it with container and operating system controls that do not depend on an in-process check being correct.
Primary sources: Node.js July 2026 security releases, NVD entry for CVE-2026-58043, and the upstream fix commit.
Resources
View All Articles


.png)