GHSA-w2vw-w76x-qr89
Nx: OS command injection via git revisions and remote refs
GHSA-w2vw-w76x-qr89 is a high vulnerability (CVSS 8.5) in nx, published October 5, 2026. No source lists public exploit code. Fixed in nx 22.7.8.
- Severity
- 8.5 HighCVSS 4.0, GitHub Advisories
- Exploit chance
- UnscoredNo EPSS score yet
- Exploitation
- None knownNot on CISA’s or ENISA’s lists
- Fixed in
22.7.8nx +3 more
Description
Summary
Nx core builds several git invocations as shell command strings with untrusted values interpolated into them, so a value that should be a git revision or ref is parsed by /bin/sh instead. Two entry points are reachable by an attacker: affected commands, where defaultBase / affected.defaultBase from nx.json (and the NX_BASE / NX_HEAD environment variables) reach git merge-base and git diff; and nx import, where a branch name advertised by a remote repository reaches git fetch, git checkout, and git config. In both cases an attacker who controls a repository — or who opens a pull request against one — gets arbitrary command execution on the machine of anyone who runs an ordinary Nx command against it, including CI runners.
The affected path is the more serious of the two. nx affected and nx show projects --affected run constantly in CI, so a pull request that changes nothing but nx.json is enough to execute code on the runner with whatever credentials that job holds.
Severity
Exploitable by anyone who controls repository content — a fork's pull request, or a repository the victim clones — that the victim then runs an ordinary nx affected or nx import against; no access to the victim's machine is required. We have no evidence of exploitation in the wild.
Affected & Patched Versions
| Package | Vulnerable | Patched |
| --- | --- | --- |
| nx | >= 14.0.0, < 22.7.8; >= 23.0.0, < 23.1.1 | 22.7.8, 23.1.1 |
Treat every version below the patched ones as affected.
Remediation
Upgrade to 22.7.8 (22.x line) or 23.1.1 (23.x line) or later:
nx migrate 23.1.1
The fix is a drop-in — no configuration changes are required. If you cannot upgrade, treat nx.json from untrusted sources as executable content, do not run affected commands against pull requests you have not reviewed, and do not run nx import against repositories you do not trust.
Details
affected commands
Nx computes the merge base and the changed-file set by building git merge-base and git diff command lines as strings and running them through a shell. The base and head revisions in those strings come from nx.json's defaultBase / affected.defaultBase or from the NX_BASE / NX_HEAD environment variables, and a related code path reads file contents with git show <revision>:<path> the same way. Because a shell parses the whole line, a revision value containing shell syntax is executed rather than passed to git.
The revisions are wrapped in double quotes, which looks protective but is not: POSIX shells still perform command substitution inside double quotes, so a value of $(…) runs without needing to break out of the quotes.
nx import
The GitRepository helper runs every git operation — fetch, checkout, reset, config, and others — by interpolating its arguments into a shell command string. The untrusted argument is a branch name: nx import lists the branches a remote advertises, offers them to the user to choose from, and feeds the chosen name back into those commands. A hostile repository controls the names of its own branches, so it controls the command that runs when one is selected.
Credits
- Arkadiusz Marta (RE:SOURCE) — Reporter
Attack profile
How easy it is to exploit
- Attack vector
- Local
- Complexity
- Low
- Privileges needed
- None
- User interaction
- Passive
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Affected packages
| Package | Affected | Fixed |
|---|---|---|
nxnpm | 14.0.0 up to 22.7.8 | 22.7.8 |
nxnpm | 23.0.0 up to 23.1.1 | 23.1.1 |
nxRoot:npm | before 15.8.7-aikido.1 | 15.8.7-aikido.114.8.9-aikido.114.8.9-aikido.219.8.14-aikido.1 |
@rootio/nxRoot:npm | before 15.8.7-root.io.1 | 15.8.7-root.io.114.8.9-root.io.114.8.9-root.io.219.8.14-root.io.1 |
What each source reports
GitHub Advisories Score used 8.5
Nx: OS command injection via git revisions and remote refs
Summary
Nx core builds several git invocations as shell command strings with untrusted values interpolated into them, so a value that should be a git revision or ref is parsed by /bin/sh instead. Two entry points are reachable by an attacker: affected commands, where defaultBase / affected.defaultBase from nx.json (and the NX_BASE / NX_HEAD environment variables) reach git merge-base and git diff; and nx import, where a branch name advertised by a remote repository reaches git fetch, git checkout, and git config. In both cases an attacker who controls a repository — or who opens a pull request against one — gets arbitrary command execution on the machine of anyone who runs an ordinary Nx command against it, including CI runners.
The affected path is the more serious of the two. nx affected and nx show projects --affected run constantly in CI, so a pull request that changes nothing but nx.json is enough to execute code on the runner with whatever credentials that job holds.
Severity
Exploitable by anyone who controls repository content — a fork's pull request, or a repository the victim clones — that the victim then runs an ordinary nx affected or nx import against; no access to the victim's machine is required. We have no evidence of exploitation in the wild.
Affected & Patched Versions
| Package | Vulnerable | Patched |
| --- | --- | --- |
| nx | >= 14.0.0, < 22.7.8; >= 23.0.0, < 23.1.1 | 22.7.8, 23.1.1 |
Treat every version below the patched ones as affected.
Remediation
Upgrade to 22.7.8 (22.x line) or 23.1.1 (23.x line) or later:
nx migrate 23.1.1
The fix is a drop-in — no configuration changes are required. If you cannot upgrade, treat nx.json from untrusted sources as executable content, do not run affected commands against pull requests you have not reviewed, and do not run nx import against repositories you do not trust.
Details
affected commands
Nx computes the merge base and the changed-file set by building git merge-base and git diff command lines as strings and running them through a shell. The base and head revisions in those strings come from nx.json's defaultBase / affected.defaultBase or from the NX_BASE / NX_HEAD environment variables, and a related code path reads file contents with git show <revision>:<path> the same way. Because a shell parses the whole line, a revision value containing shell syntax is executed rather than passed to git.
The revisions are wrapped in double quotes, which looks protective but is not: POSIX shells still perform command substitution inside double quotes, so a value of $(…) runs without needing to break out of the quotes.
nx import
The GitRepository helper runs every git operation — fetch, checkout, reset, config, and others — by interpolating its arguments into a shell command string. The untrusted argument is a branch name: nx import lists the branches a remote advertises, offers them to the user to choose from, and feeds the chosen name back into those commands. A hostile repository controls the names of its own branches, so it controls the command that runs when one is selected.
Credits
- Arkadiusz Marta (RE:SOURCE) — Reporter
- Record
GHSA-w2vw-w76x-qr89- CVSS 4.0
- 8.5 High
CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-78, CWE-88
- Updated
- 2026-11-02
OSV 8.5
Nx: OS command injection via git revisions and remote refs
Summary
Nx core builds several git invocations as shell command strings with untrusted values interpolated into them, so a value that should be a git revision or ref is parsed by /bin/sh instead. Two entry points are reachable by an attacker: affected commands, where defaultBase / affected.defaultBase from nx.json (and the NX_BASE / NX_HEAD environment variables) reach git merge-base and git diff; and nx import, where a branch name advertised by a remote repository reaches git fetch, git checkout, and git config. In both cases an attacker who controls a repository — or who opens a pull request against one — gets arbitrary command execution on the machine of anyone who runs an ordinary Nx command against it, including CI runners.
The affected path is the more serious of the two. nx affected and nx show projects --affected run constantly in CI, so a pull request that changes nothing but nx.json is enough to execute code on the runner with whatever credentials that job holds.
Severity
Exploitable by anyone who controls repository content — a fork's pull request, or a repository the victim clones — that the victim then runs an ordinary nx affected or nx import against; no access to the victim's machine is required. We have no evidence of exploitation in the wild.
Affected & Patched Versions
| Package | Vulnerable | Patched |
| --- | --- | --- |
| nx | >= 14.0.0, < 22.7.8; >= 23.0.0, < 23.1.1 | 22.7.8, 23.1.1 |
Treat every version below the patched ones as affected.
Remediation
Upgrade to 22.7.8 (22.x line) or 23.1.1 (23.x line) or later:
nx migrate 23.1.1
The fix is a drop-in — no configuration changes are required. If you cannot upgrade, treat nx.json from untrusted sources as executable content, do not run affected commands against pull requests you have not reviewed, and do not run nx import against repositories you do not trust.
Details
affected commands
Nx computes the merge base and the changed-file set by building git merge-base and git diff command lines as strings and running them through a shell. The base and head revisions in those strings come from nx.json's defaultBase / affected.defaultBase or from the NX_BASE / NX_HEAD environment variables, and a related code path reads file contents with git show <revision>:<path> the same way. Because a shell parses the whole line, a revision value containing shell syntax is executed rather than passed to git.
The revisions are wrapped in double quotes, which looks protective but is not: POSIX shells still perform command substitution inside double quotes, so a value of $(…) runs without needing to break out of the quotes.
nx import
The GitRepository helper runs every git operation — fetch, checkout, reset, config, and others — by interpolating its arguments into a shell command string. The untrusted argument is a branch name: nx import lists the branches a remote advertises, offers them to the user to choose from, and feeds the chosen name back into those commands. A hostile repository controls the names of its own branches, so it controls the command that runs when one is selected.
Credits
- Arkadiusz Marta (RE:SOURCE) — Reporter
- Record
GHSA-w2vw-w76x-qr89- CVSS 4.0
- 8.5 High
CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-78, CWE-88
- Updated
- 2026-11-02
OSVROOT-APP-NPM-GHSA-w2vw-w76x-qr89No score
GHSA-w2vw-w76x-qr89 in nx - Patched by Root
Root has patched GHSA-w2vw-w76x-qr89 in the nx package for Root:npm. Multiple fixed versions available.
- Record
ROOT-APP-NPM-GHSA-w2vw-w76x-qr89- Updated
- 2026-11-02
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | GitHub Advisories, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
References
github.com/nrwl/nx/security/advisories/GHSA-w2vw-w76x-qr89
github.com/nrwl/nx/pull/36348
github.com/nrwl/nx/pull/36379
github.com/nrwl/nx/commit/11ab38573478172109bb5306cb30ca4af246caf0
github.com/nrwl/nx/commit/4159295a037fdbd8e7f44a33a19d85ab3792415b
github.com/nrwl/nx/commit/9ce184a04d2098a4797c8b0d6877ee079b751abf
Show 7 moreShow less
github.com/nrwl/nx/commit/c12850ce7b364db08e325c13541641d754db7123
github.com/nrwl/nx/commit/cd9b3c068e17adc9c1722b35b9ca962b98542c20
github.com/nrwl/nx/commit/cf996496bbad727362d48292b50fafc8c3665847
github.com/nrwl/nx/releases/tag/22.7.8
github.com/nrwl/nx/releases/tag/23.1.1
github.com/advisories/GHSA-w2vw-w76x-qr89
github.com/nrwl/nx