CVE-2026-10796 - nvm mirror version command injection

nvm versions through 0.40.4 can execute shell commands derived from version strings returned by a configured Node.js or io.js mirror. The dangerous path is not an application runtime import; it is a developer, CI, container, or agent workspace that runs nvm install or another version-resolving nvm command against a mirror outside the default HTTPS Node.js distribution host.

This recipe treats nvm as supply-chain bootstrap code. The patch is to update nvm, but the PR also needs to remove untrusted mirror configuration and reduce the blast radius of installs that run with repository, package, cloud, or deployment credentials.

When to use it

  • A repository installs, vendors, curls, sources, or documents nvm in CI, Dockerfiles, devcontainers, Codespaces, self-hosted runners, shell profiles, release scripts, or agent workspaces.
  • Workflows run nvm install, nvm use --install, or wrappers that resolve Node.js/io.js versions from mirrors.
  • NVM_NODEJS_ORG_MIRROR or NVM_IOJS_ORG_MIRROR may point at private, mutable, internal, untrusted, or non-HTTPS mirrors.
  • You need a bounded PR or triage note that upgrades nvm and separates Node.js bootstrap from secret-bearing release/deploy jobs.

Inputs

  • Dockerfiles, devcontainers, CI workflows, runner setup scripts, shell profiles, install scripts, release jobs, .nvmrc, mirror config, generated dependency reports, SBOMs, and docs.
  • Resolved nvm versions, mirror ownership, HTTPS/immutability policy, adjacent secret names, runner cache ownership, token rotation policy, and bootstrap job boundaries.
  • Available shell/script tests, workflow lint, image builds, nvm --version checks, dependency install checks, SBOM, and security scans.

Affected versions

  • Vulnerable tool: nvm <=0.40.4
  • Fixed tool: nvm 0.40.5+
  • Affected commands: nvm install and other commands that resolve a version from a Node.js or io.js mirror index
  • Affected configuration: NVM_NODEJS_ORG_MIRROR or NVM_IOJS_ORG_MIRROR pointing at an untrusted, mutable, or non-HTTPS mirror
  • Not exposed by default: the default https://nodejs.org mirror over TLS

Indicator-of-exposure

  • The repository installs, vendors, curls, pins, or sources nvm <=0.40.4 in CI, Dockerfiles, devcontainers, bootstrap scripts, shell profiles, Codespaces setup, self-hosted runner images, or agent workspaces.
  • A controlled workflow runs nvm install, nvm use --install, or wrapper scripts that resolve Node.js versions from the network.
  • NVM_NODEJS_ORG_MIRROR or NVM_IOJS_ORG_MIRROR is configured to a private mirror, proxy, artifact cache, internal host, or http:// URL.
  • The nvm install step runs with GITHUB_TOKEN, package publish tokens, npm tokens, Git credentials, deploy keys, cloud credentials, SSH keys, model provider keys, or other secrets in the environment.
  • Build agents fetch dependencies from unreviewed forks or pull requests while also using custom nvm mirrors.

Quick checks:

rg -n "nvm|install\\.sh|NVM_NODEJS_ORG_MIRROR|NVM_IOJS_ORG_MIRROR|nvm install|nvm use --install|\\.nvmrc|node_mirror|iojs_mirror" .
rg -n "GITHUB_TOKEN|GH_TOKEN|NPM_TOKEN|NODE_AUTH_TOKEN|ACTIONS_ID_TOKEN|AWS_|AZURE_|GCP_|SSH_|DEPLOY|MODEL_|OPENAI_|ANTHROPIC_" .github Dockerfile* docker-compose*.yml devcontainer* scripts . 2>/dev/null
nvm --version

Windows:

rg -n "nvm|install\.sh|NVM_NODEJS_ORG_MIRROR|NVM_IOJS_ORG_MIRROR|nvm install|nvm use --install|\.nvmrc|node_mirror|iojs_mirror" .
rg -n "GITHUB_TOKEN|GH_TOKEN|NPM_TOKEN|NODE_AUTH_TOKEN|ACTIONS_ID_TOKEN|AWS_|AZURE_|GCP_|SSH_|DEPLOY|MODEL_|OPENAI_|ANTHROPIC_" .github Dockerfile* docker-compose*.yml devcontainer* scripts .
nvm --version

Do not run a malicious mirror, alter local PATH to fake network tools, print tokens, or capture live authorization headers during triage.

Remediation strategy

  • Upgrade every repository-controlled nvm installation to 0.40.5+.
  • Replace curl-piped installer snippets and image bootstrap scripts with a pinned release, verified checksum, or package manager source that resolves to the fixed version.
  • Remove untrusted or non-HTTPS NVM_NODEJS_ORG_MIRROR and NVM_IOJS_ORG_MIRROR settings. If a private mirror is required, require HTTPS, controlled publishing, immutable index content, and owner review.
  • Split Node.js installation from secret-bearing release, deploy, package publish, and provenance jobs where practical.
  • Add a preflight guard that fails before nvm install if the detected nvm version is below 0.40.5 or if a mirror URL is http://.
  • If the update cannot land immediately, disable custom mirrors or run nvm only in a tokenless environment until the fixed tool is installed.
  • Rotate long-lived tokens that were present when vulnerable nvm commands ran against an untrusted or non-HTTPS mirror.

The prompt

You are remediating CVE-2026-10796 / GHSA-3c52-35h2-gfmm, an nvm command
injection issue caused by trusting version strings from configured Node.js or
io.js mirrors. Produce exactly one output:

- A reviewer-ready PR/change request that upgrades every repository-controlled
  nvm installation, removes unsafe mirror configuration, adds safe preflight
  checks, refreshes generated artifacts, and documents token cleanup, or
- TRIAGE.md if this repository does not own any affected nvm installation,
  custom mirror configuration, CI image, runner bootstrap, or setup script.

## Rules

- Scope only CVE-2026-10796 / GHSA-3c52-35h2-gfmm and directly related nvm
  bootstrap, mirror, CI, container, and agent-workspace controls.
- Treat GitHub tokens, npm tokens, package-registry credentials, cloud
  credentials, deploy keys, SSH keys, model-provider keys, environment
  variables, private mirror URLs, and release artifacts as sensitive.
- Do not reproduce the command injection, run malicious mirrors, fake curl or
  wget with exploit content, capture authorization headers, print secrets, or
  execute untrusted shell snippets.
- Do not remove Node.js version management without replacing it with an
  equivalent controlled install path.
- Do not broaden token scopes or move secrets into earlier bootstrap jobs.
- Do not auto-merge.

## Steps

1. Inventory every nvm reference controlled by this repository: Dockerfiles,
   devcontainers, GitHub Actions workflows, CI templates, self-hosted runner
   scripts, agent setup scripts, shell profiles, install scripts, release
   scripts, `.nvmrc`, generated dependency reports, SBOMs, and docs.
2. Determine every resolved nvm version. A target is vulnerable if it resolves
   to `0.40.4` or earlier.
3. Search for `NVM_NODEJS_ORG_MIRROR`, `NVM_IOJS_ORG_MIRROR`, custom mirror
   variables, internal artifact-cache hosts, `http://` mirror URLs, and wrapper
   scripts around `nvm install` or `nvm use --install`.
4. Search affected install environments for secret names only:
   `GITHUB_TOKEN`, `GH_TOKEN`, `NPM_TOKEN`, `NODE_AUTH_TOKEN`, cloud
   credentials, SSH keys, deploy keys, package publish tokens, and
   model-provider keys. Never print values.
5. If the repository only contains `.nvmrc` and no controlled nvm installer,
   image, workflow, or mirror configuration, stop with `TRIAGE.md` listing the
   checked files and any external runner owner.
6. Upgrade all controlled nvm installers or vendored copies to `0.40.5+`.
   Refresh checksums, image layers, generated setup docs, SBOMs, dependency
   reports, and runner metadata.
7. Remove or harden mirror configuration:
   - prefer the default HTTPS Node.js mirror;
   - reject `http://` mirror URLs;
   - require private mirrors to be owned, immutable, HTTPS-only, and reviewed;
   - document the team that owns the mirror content.
8. Add safe preflight coverage where practical:
   - parse `nvm --version` before any version-resolving command;
   - fail closed below `0.40.5`;
   - fail closed on non-HTTPS mirrors;
   - run before secret-bearing release, deploy, or package-publish steps.
9. Reduce blast radius:
   - perform Node.js bootstrap in tokenless jobs where possible;
   - separate dependency installation from release publishing;
   - avoid custom mirrors for untrusted pull-request workflows;
   - clear persisted nvm caches from shared runner images if mirror content was
     not trusted.
10. Add a PR body section named `CVE-2026-10796 operator actions` that states:
    - nvm versions before and after;
    - where nvm is installed or sourced;
    - whether custom mirrors were present and who owns them;
    - which token-bearing environments were adjacent by secret name only;
    - whether token rotation, runner cache cleanup, or mirror audit is needed;
    - which validation commands passed.
11. Run relevant validation: shellcheck or script tests, workflow lint, image
    build, `nvm --version` checks in refreshed images, dependency install using
    the approved mirror, SBOM refresh, and dependency/security scans.
12. Use PR title:
    `fix(sec): remediate CVE-2026-10796 in nvm setup`.

## Stop conditions

- No repository-controlled nvm installer, vendored copy, workflow, runner
  image, or custom mirror configuration exists.
- nvm is supplied only by an external base image or platform owner; document
  the owner and required fixed version.
- The fixed nvm release cannot be consumed without a broader runner or image
  migration.
- Verification would require exploit mirror content, live secret-bearing
  network capture, or printing credentials.
- Validation fails for unrelated pre-existing reasons; document those failures
  instead of broadening scope.

Verification - what the reviewer looks for

  • No controlled nvm installer, vendored copy, runner image, Dockerfile, devcontainer, setup script, or CI bootstrap resolves below 0.40.5.
  • NVM_NODEJS_ORG_MIRROR and NVM_IOJS_ORG_MIRROR are absent, HTTPS-only, or explicitly owned and reviewed.
  • Affected workflows fail closed before nvm install if nvm is too old or the mirror is unsafe.
  • Secret-bearing release and deploy jobs do not run vulnerable nvm bootstrap against untrusted mirror content.
  • PR notes cover token rotation and runner-cache cleanup when exposure was plausible.

Output contract

  • Reviewer-ready PR upgrading all controlled nvm installers or vendored copies to 0.40.5+ and refreshing checksums, images, setup docs, SBOMs, and reports.
  • Mirror policy that removes unsafe custom mirrors or requires HTTPS, immutability, owner review, and fail-closed preflight checks before nvm resolves versions.
  • Reduced bootstrap blast radius by moving Node.js install away from secret-bearing release/deploy/package-publish/provenance jobs where practical.
  • TRIAGE.md when nvm is supplied only by an external base image, platform runner, or setup owner.

Watch for

  • Treating .nvmrc as the vulnerability while missing the actual nvm installer in a base image, bootstrap script, or shared runner.
  • Updating local docs but leaving CI images pinned to an old install.sh commit.
  • Allowing private mirrors over HTTP because they are “internal.”
  • Running nvm in the same step that receives package publish, deploy, or cloud credentials.
  • Validating with proof-of-concept mirror content instead of safe version and configuration checks.

References