GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||||
GeezerVison is showing github.com — chore(deps): update dependency nx to v22.7.10 [security] by renovate[bot] · Pull Request #520 · TanStack/devtools Conversation
|
| Package | Change | Age | Confidence |
|---|---|---|---|
| nx (source) | 22.1.3 → 22.7.10 |
nx graph dev server permissive CORS policyCVE-2026-54753 / GHSA-g2r8-wvmj-jf5w
The local HTTP server started by nx graph sent Access-Control-Allow-Origin: * on every response, letting any website a developer visited read the server's responses cross-origin — including the full project graph and the output of the /help endpoint, which runs a target's configured help command. The practical impact is typically cross-origin information disclosure, but can be arbitrary command injection in rare cases.
Exploitation requires the developer to be running nx graph and to visit an attacker page. Any execution beyond benign help commands also requires a malicious target to already be present in the workspace (see Details).
Package: nx (npm).
>= 17.0.4, < 22.7.2 and >= 23.0.0-beta.0, < 23.0.0-beta.222.7.2+ (backport) and 23.0.0 (first in 23.0.0-beta.2)The wildcard CORS header was introduced in 17.0.4; the /help execution endpoint in 19.4.0. The 21.x line is not patched — 21.x users should upgrade to 22.7.2 or later.
nx graph starts a local server (default http://127.0.0.1:4211). Before the fix, its request handler set a wildcard CORS header on every response:
res.setHeader('Access-Control-Allow-Origin', '*');
The /help endpoint runs a target's configured command:
const command = target.metadata?.help?.command; return execSync(command, { cwd: target.options?.cwd ?? workspaceRoot }).toString();
A GET /help is a CORS "simple request", so a malicious page could fetch() it with no preflight, and the wildcard header let the page read the result. This exposes the project graph (project names, file paths, dependencies, build configuration) and the output of any configured help command.
The command is not attacker-controlled through the request — it comes from the workspace's project configuration, and first-party plugins (jest, vite, cypress) populate it with benign, read-only help commands. For /help to run anything malicious, a target carrying a malicious help.command must already exist in the project graph, which can only be introduced by installing a malicious package or by altering the workspace's own code/configuration — both of which already grant code execution independent of this flaw.
The fix (#35494) removes the header; the browser's same-origin policy then blocks cross-origin reads.
/help)Thanks to Nozomu Sasaki (Paul) (@morimori-dev) for finding and responsibly reporting this issue.
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:L/A:NThis data is provided by the GitHub Advisory Database (CC-BY 4.0).
CVE-2026-71476 / GHSA-vp3h-ghgh-jr7g
The Nx self-hosted HTTP remote cache extracts downloaded cache artifacts without constraining where files are written. A malicious — or on-path (MITM) — remote cache server can return a crafted tar archive whose entries escape the cache directory and write to arbitrary locations on the machine running Nx. This arbitrary file write can be escalated to remote code execution. The directly exploitable issue is the self-hosted HTTP remote cache.
[!IMPORTANT]
Nx's default local cache and Nx Cloud are NOT affected. The default local cache and Nx Cloud use separate cache retrieval and extraction mechanisms that does not have this vulnerability. Only workspaces that use a self-hosted remote cache (NX_SELF_HOSTED_REMOTE_CACHE_SERVER,@nx/s3-cache, etc.) are affected.
Two self-hosted cache surfaces are affected:
NX_SELF_HOSTED_REMOTE_CACHE_SERVER, in nx) — fixed in the patched release.@nx/s3-cache, @nx/gcs-cache, @nx/azure-cache, @nx/shared-fs-cache (and their @nx/powerpack-* predecessors) — the same flaw in their own extractor. Deprecated (CVE-2025-36852) and not patched; migrate off (see Remediation).The shared step that copies cached outputs into the workspace was also part of the exposure and is hardened in the patched nx release.
Upgrade to Nx 22.7.7 or 23.0.2 (or later). The patched extractor is a drop-in — no configuration change is required.
@nx/s3-cache, @nx/gcs-cache, @nx/azure-cache, and @nx/shared-fs-cache (and their @nx/powerpack-* predecessors) are separately versioned packages and are already deprecated (see CVE-2025-36852). Upgrading nx hardens the shared restore step, but it does not fully secure these packages. The remediation for them is to migrate off — to Nx Cloud or the self-hosted OpenAPI/HTTP remote cache — per the deprecation guidance: https://nx.dev/docs/reference/deprecated/self-hosted-cache-packages
When Nx retrieves an artifact from the self-hosted HTTP remote cache, it downloads a gzipped tar archive and extracts it. The extractor joined each untrusted tar entry name directly onto the output directory and unpacked it with tar's unguarded Entry::unpack(), which performs no containment check:
// vulnerable let path_on_disk = output_dir.join(entry_path); // entry_path is attacker-controlled fs::create_dir_all(path_on_disk.parent()…)?; entry.unpack(&path_on_disk)?;
In addition, restore now copies only the declared task outputs (never the whole cache directory), confined to the workspace root; parent directories are realized as real directories so a write can never traverse a symlink; declared outputs that resolve outside the workspace are rejected; and the malformed-input cases return errors instead of panicking.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:NThis data is provided by the GitHub Advisory Database (CC-BY 4.0).
CVE-2026-104853 / GHSA-hrvq-x7jp-36xv
nx migrate reads each target package's nx-migrations.migrations value from its manifest and extracts the referenced file to a path built by joining that value onto a temporary directory. The value is never validated, so a package whose migrations field contains .. segments (or an absolute path) steers the extraction to write outside the temporary directory. A hostile package — or any package pulled in transitively through a trusted package's packageGroup — can write attacker-controlled content, or truncate an existing file, anywhere the running user can write. This happens during migration planning, before the user reviews the migration list and before --run-migrations, so it does not require the user to approve or execute anything.
Most workspaces need no action. By default nx migrate does not run the nx installed in your workspace — it installs nx@latest into a temporary directory and performs the upgrade planning, including this extraction, with that copy. Now that a patched nx is the latest release, a default nx migrate run is unaffected whatever version the workspace has installed. The installed version only runs, and is only then exposed, when that hand-off is bypassed — see Remediation.
Exploitable when the victim runs nx migrate against a package the attacker controls, directly or through a trusted package's packageGroup. The primary impact is a file write with attacker-controlled content and no path confinement; overwriting an auto-loaded file (a shell rc, a git hook, a CI script) escalates that write to code execution. There is no known evidence of exploitation in the wild.
| Package | Vulnerable | Patched |
|---|---|---|
nx |
>= 13.10.0, < 22.7.10; >= 23.0.0, < 23.2.1 |
22.7.10, 23.2.1 |
Every version in the ranges above is affected. The lower bound is 13.10.0, the first release where nx migrate extracted a package's migrations file from its tarball; earlier versions resolved migrations without that extraction.
[!IMPORTANT]
nx migratenormally fetches and runsnx@latestrather than the nx installed in your workspace. The ranges above therefore say where the vulnerable code ships, not who is exposed — it only runs when that hand-off is bypassed.
If you run nx migrate normally, there is nothing to do. It resolves and runs the latest nx, which is patched, so your workspace's own nx version does not matter for this flaw.
Upgrade only if you bypass that hand-off and run the workspace's nx instead — that is, if you set NX_USE_LOCAL or NX_MIGRATE_USE_LOCAL, pin NX_MIGRATE_CLI_VERSION to an affected version, resume an existing run with --run-id, or run where the temporary install fails and nx migrate falls back to the local nx. In those cases upgrade to 22.7.10 (22.x line) or 23.2.1 (23.x line) or later:
nx migrate 23.2.1
The fix is a drop-in — no configuration changes are required, and no legitimate migrations value is affected (real packages reference ./migrations.json or another path within their own directory, all of which remain valid). Either way, do not run nx migrate against packages, or packageGroup members, that you do not trust.
While planning an upgrade, nx migrate extracts each target package's migrations file to a destination built by joining the package's own nx-migrations.migrations value onto a temporary directory. That value is read from the manifest without validation, and it is handled asymmetrically: the name Nx matches against the archive entries is normalized (so its .. segments collapse), while the destination path it writes to is a raw join that keeps the .. segments and resolves outside the temporary directory. Because the attacker controls the tarball, they name their entry to equal the normalized form; the match then succeeds and the bytes are written to the un-normalized, escaping destination. The normalization is not a defence — it only dictates what the attacker must name their entry.
The same value also seeds the directory used for prompt-file extraction, which has the same shape, so both writes are steerable from the one field.
Two distinct primitives fall out of this:
migrations at an existing file empties that file even when no tar entry matches — no crafted archive required.CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:P/VC:L/VI:H/VA:L/SC:N/SI:N/SA:NThis data is provided by the GitHub Advisory Database (CC-BY 4.0).
CVE-2026-104854 / GHSA-w3vv-58gj-gw77
Nx creates the Unix domain sockets for its daemon and its plugin workers in a shared temporary directory with default permissions, so any other user on the same machine can connect to them. The daemon accepts a PROCESS_IN_BACKGROUND request that names a module to load and invokes its default export, which turns socket access into code execution inside the daemon process. On a multi-user machine — a shared build server, a shared developer box, or a container running several accounts — one local user can execute code as another user running Nx.
Exploitable by any other unprivileged local user on a shared host while a daemon or plugin worker is running, with no user interaction. There is no known evidence of exploitation in the wild.
| Package | Vulnerable | Patched |
|---|---|---|
nx |
>= 14.6.0, < 22.7.9; >= 23.0.0, < 23.1.2 |
22.7.9, 23.1.2 |
Every version in the ranges above is affected. The lower bound is 14.6.0, when the daemon request handler that turns socket access into code execution was added.
[!IMPORTANT]
Single-user machines are not exposed. The vulnerability requires another local account on the same host, so an ordinary laptop with one user account is unaffected — the exposure is shared CI runners, shared build and development servers, and containers or images that run more than one uid.Disabling the daemon is not sufficient on its own: the plugin worker sockets used by plugin isolation are created in the same directory with the same permissions, and those are used during normal command runs whether or not the daemon is enabled.
Upgrade to 22.7.9 (22.x line) or 23.1.2 (23.x line) or later:
nx migrate 23.1.2
On a shared machine, run nx reset after upgrading so that any sockets and directories created by an older version are removed rather than reused.
If you cannot upgrade, point NX_SOCKET_DIR at a directory you own with mode 0700, which is already honoured by the vulnerable versions, and disable the daemon with NX_DAEMON=false to reduce the reachable surface — though, per the callout above, that does not remove the plugin worker sockets.
The daemon and the plugin workers communicate over Unix domain sockets placed in a subdirectory of the shared OS temporary directory. That directory is created with default permissions, which on a typical system leave it readable and traversable by every user on the machine, and nothing narrows the socket files themselves. The directory name is derived from a hash of the workspace path and the process id, so it is unique but not secret — any local user who lists the temporary directory can find it.
The connection carries no authentication: the containment is meant to be the filesystem permissions alone, and those are too broad. Any local process that can reach the socket is treated as a fully trusted client.
The impact of that access is set by what the daemon's request handlers allow. One handler takes a module path from the request and loads and invokes it; because an absolute path resolves regardless of the lookup constraints in place, a caller who can write a file anywhere on the machine — their own home directory suffices — and connect to the socket can have the daemon execute it, as the user running the daemon. Other handlers expose workspace file contents, the project graph, and task hashes to the same unauthenticated caller.
Reported by researchers at the University of Sydney:
CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:NThis data is provided by the GitHub Advisory Database (CC-BY 4.0).
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.
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.
| 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.
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.
affected commandsNx 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 importThe 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.
CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:NThis data is provided by the GitHub Advisory Database (CC-BY 4.0).
v22.7.10v22.7.9v22.7.8v22.7.7v22.7.6v22.7.5v22.7.4v22.7.3projects: 'self' in dependsOn entries (#35686)$ escaping in file paths on windows (#35692)v22.7.2nx mcp to run outside of an Nx workspace (#35655)v22.7.1[!IMPORTANT]
✂ PR body was truncated to here.
📅 Schedule: (UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
6b20283 to
ca6f5e4
Compare
There was an error while loading. Please reload this page.
|
Important Review skippedBot user detected. To trigger a single review, invoke the
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
ca6f5e4 to
961bc1f
Compare
961bc1f to
a8ae27b
Compare
There was an error while loading. Please reload this page.
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
a8ae27b to
0a6b284
Compare
0a6b284 to
d183eba
Compare
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.