GHSA-r275-fr43-pm7q simple-git has blockUnsafeOperationsPlugin bypass via case-insensitive protocol.allow config key enables RCE
SummaryThe `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.DetailsThe `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: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:****The fix is a single character — add the `/i` flag:**poc.jsTest ResultsVector 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:**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:**`/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:**`/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    | ✅              |ImpactAny 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.
CVSS v3.1 score: 9.8