Introduction
An incomplete security fix in the simple-git npm package has reopened a critical remote code execution path that was supposed to have been closed in 2022. CVE-2026-6951, with a CVSS 3.1 score of 9.8, lets an attacker bypass argument filtering and execute arbitrary commands on the host system. All it takes is switching from the short-form -c flag to the long-form --config flag when injecting git configuration overrides.
simple-git is a widely used Node.js library that provides a lightweight programmatic interface for running git commands. It has over 8.7 million weekly downloads and 7,789 dependent packages on npm, and it sits at the center of a lot of the JavaScript ecosystem's build and deployment tooling. A vulnerability at this layer reaches far down the supply chain.
Technical Information
CVE-2026-6951 comes from how simple-git parses and filters arguments before passing them to the underlying git binary. In 2022, CVE-2022-25912 was disclosed because attackers could use the -c flag to override git configuration at runtime, specifically enabling protocol.ext.allow=always to activate the ext:: remote helper protocol. The ext:: protocol is a git feature that executes arbitrary shell commands as part of a remote URL, so combined with configuration injection it is a well-known code execution vector.
The mitigation for CVE-2022-25912 added a blocklist that intercepted the short -c option. It did not account for the long-form --config flag, which does exactly the same thing. Because git treats -c key=value and --config key=value identically, an attacker could switch to --config and sail right past the filter.
Attack Flow
The exploitation path is straightforward:
- The attacker identifies a Node.js application that uses
simple-gitand passes user-controlled input into theoptionsorcustomArgsparameters of a git operation such asclone. - The attacker supplies
--configandprotocol.ext.allow=alwaysas options. The blocklist does not intercept these because it only checks for-c. - The attacker provides a malicious clone URL using the
ext::protocol, embedding an arbitrary shell command within the URL. simple-gitpasses these arguments unmodified to thegitbinary, which honors the config override, enables theext::protocol, and executes the embedded command with the privileges of the Node.js process.
This is not the only bypass of its kind. A related vulnerability, CVE-2026-28292, used uppercase characters (PROTOCOL.ALLOW=always) to evade case-sensitive regex checks in the blockUnsafeOperationsPlugin. Between them, the two bypasses show how fragile regex-based argument filtering is as a security boundary.
Patch Information
The fix for CVE-2026-6951 is implemented in commit 89a2294, authored by Steve King on April 11, 2026, and shipped in simple-git version 3.36.0 (released April 12, 2026). The commit is titled "Environment Parsing (#1156)" and touches 29 files with over 1,000 lines of additions. It is a substantial rework of how the library detects and blocks dangerous arguments.
The patch does considerably more than add --config to the blocklist. The main architectural changes follow.
Expanded Config Key Blocklist
The old detect-config-writes.ts only blocked six config keys: protocol.allow, core.sshCommand, core.fsmonitor, core.gitProxy, core.hooksPath, and diff.external. The replacement file, detect-vulnerable-config-writes.ts, introduces a much broader blocklist. A new helper called preventExpandedConfigBuilder uses regex expansion so that patterns like credential.helper also match scoped variants (e.g., credential.https://example.com.helper). The new blocklist covers:
alias.*(arbitrary command aliases)core.askPass,core.editor,core.pager(binary substitution vectors)credential.helper(credential interception)diff.textconv,diff.command,filter.clean,filter.smudge(file content interception)gpg.program,gpg.ssh.program,gpg.x509.program(signing binary substitution)init.templateDir(hook planting via templates)merge.driver,mergetool.cmd,mergetool.path(merge-time code execution)remote.*.receivepack,remote.*.uploadpack(per-remote pack binary overrides)sequence.editor(rebase-time binary substitution)
Expanded Flag Detection
The old detect-upload-pack.ts only flagged --upload-pack, --receive-pack, and related options. The new detect-vulnerable-flags.ts adds --template to the flag blocklist, which blocks template directory injection from the command line as well as through config.
New Environment Variable Scanning
This part is entirely new. The commit introduces parseEnv(), which inspects the environment variables passed to the git child process. It maps security-sensitive environment variable names (like GIT_ASKPASS, GIT_SSH_COMMAND, GIT_CONFIG_COUNT, GIT_EXTERNAL_DIFF, GIT_TEMPLATE_DIR, GIT_PROXY_COMMAND, EDITOR, PAGER, etc.) to their vulnerability categories. When GIT_CONFIG_COUNT is set, the parser reads the matching GIT_CONFIG_KEY_n / GIT_CONFIG_VALUE_n pairs and runs those injected keys through the same blocklist checks as inline -c values.
Unified Vulnerability Check Entry Point
A new vulnerabilityCheck(tokens, env) function combines argument parsing and environment scanning in one call. The block-unsafe-operations-plugin.ts action handler now receives the task's environment context and passes it into this unified check:
// Before (only checked args): action(args) { const parsed = parseArgv(...args); for (const vulnerability of parsed.vulnerabilities.vulnerabilities) { ... } } // After (checks args AND environment): action(args, { env }) { for (const vulnerability of vulnerabilityCheck(args, env)) { ... } }
So if an attacker gets around the argument-level protections by injecting config through environment variables (for example, setting GIT_CONFIG_COUNT=1 plus GIT_CONFIG_KEY_0=protocol.ext.allow and GIT_CONFIG_VALUE_0=always), the library will still detect and block the attempt.
Granular Opt-In Model
Each new blocked category has a matching opt-in flag (e.g., allowUnsafeAlias, allowUnsafeCredentialHelper, allowUnsafeTemplateDir, etc.) in the unsafe configuration object. Developers who genuinely need one of these features with trusted input have explicit control over turning it back on. The VulnerabilityCategoryFlags interface grew from 7 categories in the previous version to over 20.
To remediate, upgrade to simple-git version 3.36.0 or later:
npm install simple-git@latest
When you upgrade, make sure transient dependencies are fully updated too. Maintainers reported that partial upgrades, which left @simple-git/argv-parser mismatched, caused breaking TypeError issues in CI environments.
Affected Systems and Versions
All versions of the simple-git npm package prior to version 3.36.0 are affected. The vulnerability is exploitable in any Node.js application where untrusted user input can reach the options or customArgs parameters of simple-git functions such as clone.
Version 3.36.0, released on April 12, 2026, contains the fix.
Vendor Security History
The simple-git project has had repeated security bypasses, all stemming from its reliance on blocklist-based argument filtering:
- CVE-2022-25912: The original RCE via
-cflag injection enabling theext::protocol. This is the vulnerability that CVE-2026-6951 bypasses. - CVE-2026-28292: A bypass using uppercase characters (
PROTOCOL.ALLOW=always) to evade case-sensitive regex checks in theblockUnsafeOperationsPlugin. - CVE-2026-6951: The current vulnerability, bypassing the
-cblocklist via the equivalent--configflag.
To the maintainer's credit, each fix has been more comprehensive than the last. The patch for CVE-2026-6951 is a significant architectural improvement. It replaces narrow blocklist entries with a defense-in-depth approach that covers config keys, command-line flags, and environment variables at the same time.
References
- NVD: CVE-2026-6951
- CVE Record: CVE-2026-6951
- Snyk: Remote Code Execution (RCE) in simple-git
- GitHub Gist: RCE in simple-git by KKC73
- Fix Commit: Environment Parsing (#1156)
- Patch File for Commit 89a2294
- simple-git Releases
- Snyk: CVE-2022-25912 (Original RCE)
- GitHub Advisory: CVE-2026-28292
- Pull Request #1156: Environment Parsing
- simple-git on npm
- steveukx/git-js on GitHub



