ZeroPath at Black Hat USA 2026

nvm CVE-2026-10796: Brief Summary of Dual Command Injection via Malicious Mirror Version Strings

A brief summary of CVE-2026-10796, a CVSS 7.5 command injection vulnerability in nvm through version 0.40.4 where unsanitized version strings from mirror index.tab files can achieve arbitrary code execution through two distinct sinks in nvm_download() and nvm_get_checksum().

CVE Analysis

8 min read

ZeroPath CVE Analysis
ZeroPath CVE Analysis

2026-06-04

nvm CVE-2026-10796: Brief Summary of Dual Command Injection via Malicious Mirror Version Strings
Experimental AI-Generated Content

This CVE analysis is an experimental publication that is completely AI-generated. The content may contain errors or inaccuracies and is subject to change as more information becomes available. We are continuously refining our process.

If you have feedback, questions, or notice any errors, please reach out to us.

[email protected]

Introduction

A dual sink command injection in nvm (Node Version Manager) allows an attacker who controls a configured mirror to execute arbitrary commands on any machine running nvm install, simply by embedding shell metacharacters in version strings served through the mirror's index.tab file. For the millions of developers and CI/CD pipelines relying on nvm to manage Node.js installations, this vulnerability turns a routine version management operation into a potential remote code execution vector whenever a non default or non TLS mirror is in use.

nvm is the de facto standard tool for Node.js version management on macOS and Linux. With approximately 93,700 GitHub stars and 10,200 forks, it is one of the most widely adopted developer tools in the JavaScript ecosystem. Its single shell script architecture and ubiquitous presence in CI/CD pipelines, Docker images, and developer workstations make it a critical piece of infrastructure for Node.js development workflows globally.

Technical Information

CVE-2026-10796 is classified as CWE-78: Improper Neutralization of Special Elements used in an OS Command with a CVSS v3.1 base score of 7.5 (High) and vector CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H. The vulnerability affects nvm through version 0.40.4.

Root Cause

When a user runs nvm install <version>, nvm fetches the configured mirror's index.tab file to enumerate available Node.js and io.js versions. The selected version string is then used, without any sanitization, to build download URLs and construct shell and awk commands. The core architectural flaw is the use of eval for command execution and direct string interpolation into awk programs, both of which treat untrusted mirror data as trusted code.

Dual Injection Sinks

Two distinct code paths in nvm serve as injection sinks for the same untrusted input:

Sink 1: eval in nvm_download()

The nvm_download() function constructed a curl or wget command string and executed it using eval. Because the version string from the mirror was interpolated directly into this command string, a version field containing shell command substitution (for example, $(id)) would be executed by the local shell before curl or wget ever ran. Double quoting arguments inside eval did not prevent command substitution, bypassing an earlier quoting hardening from commit 0ce8f5a.

Sink 2: awk interpolation in nvm_get_checksum()

The nvm_get_checksum() function interpolated the version derived download slug (the tarball name) directly into an awk program text. A crafted version string such as:

v1"==$2){system("touch${IFS}/tmp/proof")}#

could break out of the awk string literal and invoke awk's system() function, achieving arbitrary command execution entirely through the awk interpreter without involving the shell's eval at all.

Attack Flow

The exploitation sequence proceeds through the following steps:

  1. Mirror control: The attacker establishes control over mirror content. This can be achieved by operating a malicious mirror, compromising an existing corporate or internal mirror, performing a man in the middle attack on a non TLS (HTTP) mirror connection, or through DNS poisoning.

  2. Payload delivery: The attacker crafts a malicious index.tab file containing version strings with embedded shell metacharacters or awk escape sequences. The poisoned version entry appears as a normal Node.js version to the user.

  3. Trigger: When a victim runs nvm install, nvm fetches the index.tab from the configured mirror and parses the version list. The user selects (or nvm automatically resolves) the poisoned version.

  4. Execution: The unsanitized version string flows into either nvm_download() (where eval executes the embedded command substitution) or nvm_get_checksum() (where awk string interpolation triggers system() execution). In both cases, the injected commands run with the full privileges of the user running nvm.

Attack Vector Summary

VectorMechanismComplexityAffected Configurations
Malicious mirror operatorMirror serves crafted index.tab with poisoned version stringsLowAny user pointing to that mirror
Mirror content supplyAttacker provides or alters content served on a non default mirrorMediumCorporate/internal mirrors with weak access controls
MITM on non TLS mirrorAttacker intercepts HTTP mirror connection and injects crafted index.tabMediumhttp:// mirror URLs without TLS
DNS poisoningAttacker redirects mirror hostname to attacker controlled serverHighAny mirror using DNS resolvable hostnames

The default mirror (https://nodejs.org over TLS) is explicitly not affected, as TLS protects against MITM and the Node.js project controls its own index.tab content.

Relationship to CVE-2026-1665

This vulnerability is directly related to CVE-2026-1665 (CVSS 5.4), which was published on January 29, 2026 and affected nvm versions 0.40.3 and below. That earlier CVE exploited the NVM_AUTH_HEADER environment variable, which was unsanitized in the wget code path but sanitized in the curl code path. It was patched in nvm v0.40.4.

However, the v0.40.4 patch was incomplete. It addressed the specific unsanitized NVM_AUTH_HEADER variable without removing the underlying eval mechanism in nvm_download(). CVE-2026-10796 exploits the same eval sink but through a different input vector: remote mirror supplied version strings rather than a local environment variable. This makes CVE-2026-10796 more dangerous in network facing scenarios, as the attacker does not need local access to set environment variables.

The discovery of CVE-2026-10796 was credited to @DavidCarliez for reporting the eval sink in nvm_download(). The awk injection sink in nvm_get_checksum() was discovered during an internal audit prompted by the initial external report.

Affected Systems and Versions

Affected: nvm (Node Version Manager) versions through 0.40.4 (all versions up to and including 0.40.4).

Fixed in: nvm version 0.40.5.

Vulnerable configurations: Any nvm installation where one or more of the following conditions apply:

  • The NVM_NODEJS_ORG_MIRROR environment variable is set to a non default mirror URL
  • The NVM_IOJS_ORG_MIRROR environment variable is set to a non default mirror URL
  • A mirror URL uses http:// rather than https://
  • The configured mirror is operated by an untrusted party or has weak access controls

Not affected: Installations using the default mirror (https://nodejs.org over TLS) with no custom mirror environment variables set.

Note: nvm for Windows (coreybutler/nvm-windows) is a separate project and is not affected by this CVE.

Vendor Security History

nvm's security track record reveals a recurring pattern of command injection vulnerabilities stemming from the use of eval for command construction:

CVEDate PublishedCVSSAffected VersionsRoot CauseFix Version
CVE-2026-16652026-01-295.4 (v4.0)0.40.3 and belowUnsanitized NVM_AUTH_HEADER in wget path via eval0.40.4
CVE-2026-107962026-06-047.5 (v3.1)0.40.4 and belowUnsanitized version strings from mirror index.tab via eval and awk interpolation0.40.5

The OpenCVE database listed only one nvm CVE prior to CVE-2026-10796. The progression from CVE-2026-1665 to CVE-2026-10796 illustrates a common pattern: patching individual unsanitized inputs without removing the evaluative execution mechanism is insufficient when multiple untrusted data flows converge on the same sink. The v0.40.5 fix takes a more thorough approach by eliminating eval entirely, restructuring awk data flow, and adding input validation as defense in depth.

The nvm project supports private vulnerability reporting through GitHub, email to ljharb, and through Tidelift.

References

Detect & fix
what others miss

Works with
  • GitHub
  • GitLab
  • Bitbucket
  • Azure DevOps Services
  • Jira
  • Linear
  • Slack
  • Security Compass
Security magnifying glass visualization