# GitHub - RCE via git option injection (almost) - $20,000 Bounty

Git option injection via wiki branch names let --output write attacker-controlled diff content into sourced env.d scripts, achieving RCE on GitHub Enterprise.

- Payout: $20,000
- Severity: high
- Program: GitHub
- Credited: William Bowling / vakzz
- Disclosed: 2020-10-18
- Write-up quality: 9/10
- Original: https://devcraft.io/2020/10/18/github-rce-git-inject.html
- Library page: https://bugbountylibrary.com/r/blog%3Adevcraft-io-2020-10-18-github-rce-git-inject-html
- Tags: domain:web impact:rce kind:bounty platform:blog sev:high tech:ruby technique:chained technique:source-review vuln:command-injection vuln:csrf

**Target:** GitHub Enterprise wiki revert endpoint / git diff-tree subcommand
**Root cause:** reverse_diff passed user-controlled commitish values (branch names) to git diff-tree without a `--` separator or leading-dash check, so a branch named `--output=/path` was parsed as a git option.
**Steps:**
1. Decode GHE obfuscated Ruby to source; grep for git process invocations and trace args to user input.
2. Find reverse_diff called by revert_range on POST user/repo/wiki/Home/_revert/<c1>/<c2>; only check is valid git ref.
3. Push branch `--output=/tmp/ggg` via `git push origin master:--output=/tmp/ggg`.
4. POST to `/user/repo/wiki/Home/_revert/HEAD/--output%3D%2Ftmp%2Fggg` with a valid authenticity_token (per-form CSRF blocks normal path; global token pulled from DB for PoC).
5. Observe git diff-tree writes diff output to /tmp/ggg.
6. Point --output at a sourced env.d script path e.g. `/data/failbotd/shared/env.d/00-run.sh`; craft wiki content so diff body contains valid shell (`; echo vakzz was here > /tmp/ggg`).
7. Trigger sourcing of the env.d script; shell executes injected line despite diff noise.
**How found:** Recalled a prior GitHub bug about branch names starting with `-` injecting git options; systematically grepped all git invocations, traced args for user control and sanitisation, and found reverse_diff lacked `--`/dash checks. Then used execsnoop to see the exact git command and abused diff-tree's --output flag.
**Exploitation:** Attacker with repo access pushes a branch named as a git flag, then hits the wiki revert endpoint with a valid CSRF token so git diff-tree writes a partially attacker-controlled diff into a startup-sourced env.d shell script, yielding command execution as the git service user.
**Escalation:** Chained file-write primitive into RCE by targeting env.d directories whose *.sh files are sourced at service start; bash continues past errors so diff noise doesn't block the injected command.
**Insight:** When auditing git wrappers, look for commitish/branch/tag values reaching subcommands without `--`; git options like --output, --upload-pack, -c turn ref injection into file write or command exec. Also check whether written files land in sourced env.d/startup script directories.
