# Git option denylist bypass

Security gates matching literal git flags; check config includes, joined short options, and long-option abbreviations

_Area: Software supply chain and CI/CD. Seen in 3 disclosed reports; latest 2026-10-05. Updated 2026-10-24._

## How it works

A library wraps git and tries to block dangerous options by matching the option names it sees in attacker-influenced arguments (customArgs, multi_options). The gate assumes the option name it parses equals the option git will act on. Git accepts many spellings for one option: `-cKEY=VALUE` joined, `-uVALUE` joined, and unambiguous long-option prefixes like `--receive-p` or `--exe`. If the gate compares literal strings or canonicalizes only some forms, a spelling git honors slips past. Separately, a denylist of dangerous config keys is only as good as its coverage of the key namespace; `include.path` and `includeIf.<cond>.path` load arbitrary gitconfig, which can set `core.sshCommand` and run code [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-g4wm-2vf7-vfgr.md).

## Where it shows up

- Denylists of git config keys passed via `-c`; check for `include.path` and `includeIf.*.path` [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-g4wm-2vf7-vfgr.md)
- Option validators that run after `shlex.split` but canonicalize joined short options to `uVALUE` instead of `u` [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-v396-v7q4-x2qj.md)
- Filters matching literal flag names (`--upload-pack`, `--exec`) without expanding git's prefix abbreviations [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-858h-whjf-mvg5.md)
- Regex built from a denylist string via `new RegExp(string)`: dots become wildcards, match is unanchored [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-g4wm-2vf7-vfgr.md)
- Any wrapper exposing `clone`, `mirror`, `push` with caller-supplied extra args

## How to review

The invariant: every argument form git accepts for a dangerous option must map to the same blocked canonical name before the decision. Check that the gate (1) canonicalizes joined short options to their bare letter, (2) resolves long-option prefixes to the full option name, and (3) blocks the whole config-include namespace, not just listed keys. Prefer an allowlist of permitted options over a denylist. Verify the check runs on the final argv actually passed to git, not a pre-split string.

## Variants seen

- Config-key denylist missing `include.path`/`includeIf` [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-g4wm-2vf7-vfgr.md)
- Joined short option `-u<helper>` bypassing the `-u` block [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-v396-v7q4-x2qj.md)
- Long-option abbreviation `--receive-p`/`--exe` bypassing literal match [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-858h-whjf-mvg5.md)

## Why fixes fail

E1's pending fix used an unanchored regex where dots act as wildcards, leaving variants open [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-g4wm-2vf7-vfgr.md). E3 is described as a residual of an earlier CVE, showing the literal-match fix did not cover abbreviations [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-858h-whjf-mvg5.md).

## Impact and severity

Each bypass led to command execution in the consuming application [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-g4wm-2vf7-vfgr.md)[E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-v396-v7q4-x2qj.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-858h-whjf-mvg5.md). Severity is high: the wrapper is the trust boundary, and callers pass untrusted args believing they are sanitized. Worse when the library is a transitive dependency of build or release tooling.

## Evidence
- E1: https://bugbountylibrary.com/r/ghsa%3AGHSA-g4wm-2vf7-vfgr.md
- E2: https://bugbountylibrary.com/r/ghsa%3AGHSA-v396-v7q4-x2qj.md
- E3: https://bugbountylibrary.com/r/ghsa%3AGHSA-858h-whjf-mvg5.md
