GHSA-rpm5-65cw-6hj4: GitPython has Command Injection via Git options bypass
SummaryGitPython blocks dangerous Git options such as `--upload-pack` and `--receive-pack` by default, but the equivalent Python kwargs `upload_pack` and `receive_pack` bypass that check. If an application passes attacker-controlled kwargs into `Repo.clone_from()`, `Remote.fetch()`, `Remote.pull()`, or `Remote.push()`, this leads to arbitrary command execution even when `allow_unsafe_options` is left at its default value of `False`.DetailsGitPython explicitly treats helper-command options as unsafe because they can be used to execute arbitrary commands:`git/repo/base.py:145-153` marks clone options such as `--upload-pack`, `-u`, `--config`, and `-c` as unsafe.`git/remote.py:535-548` marks fetch/pull/push options such as `--upload-pack`, `--receive-pack`, and `--exec` as unsafe.The vulnerable API paths check the raw kwarg names before they're its normalized into command-line flags:`Repo.clone_from()` checks `list(kwargs.keys())` in `git/repo/base.py:1387-1390``Remote.fetch()` checks `list(kwargs.keys())` in `git/remote.py:1070-1071``Remote.pull()` checks `list(kwargs.keys())` in `git/remote.py:1124-1125``Remote.push()` checks `list(kwargs.keys())` in `git/remote.py:1197-1198`That validation is performed by `Git.check_unsafe_options()` in `git/cmd.py:948-961`. The validator correctly blocks option names such as `upload-pack`, `receive-pack`, and `exec`.Later, GitPython converts Python kwargs into Git command-line flags in `Git.transform_kwarg()` at `git/cmd.py:1471-1484`. During that step, underscore-form kwargs are dashified:`upload_pack=...` becomes `--upload-pack=...``receive_pack=...` becomes `--receive-pack=...`Because the unsafe-option check runs before this normalization, underscore-form kwargs bypass the safety check even though they become the exact dangerous Git flags that the code is supposed to reject.In practice:`remote.fetch(**{"upload-pack": helper})` is blocked with `UnsafeOptionError``remote.fetch(upload_pack=helper)` is allowed and reaches helper executionThe same bypass works for:This does not appear to affect every unsafe option. For example, `exec=` is already rejected because the raw kwarg name `exec` matches the blocked option name before normalization.Existing tests cover the hyphenated form, not the vulnerable underscore form. For example:`test/test_clone.py:129-136` checks `{"upload-pack": ...}``test/test_remote.py:830-833` checks `{"upload-pack": ...}``test/test_remote.py:968-975` checks `{"receive-pack": ...}`Those tests correctly confirm the literal Git option names are blocked, but they do not exercise the normal Python kwarg spelling that bypasses the guard.PoCCreate and activate a virtual environment in the repository root:make a new python file and put the following in there, then run it:Expected result:The script prints `control=blocked`The script prints `proof_exists True ...`The proof file contains evidence that the attacker-controlled helper executed as the local application account, including `id`, working directory, argv, and selected environment variable namesExample output:This PoC does not require a malicious repository. The PoC uses that fresh blank repository. The only attacker-controlled input is the kwarg that GitPython turns into `--upload-pack`.ImpactWho is impacted:Web applications that let users configure repository import, sync, mirroring, fetch, pull, or push behaviorSystems that accept a user-provided dict of "extra Git options" and pass it into GitPython with `**kwargs`CI/CD systems, workers, automation bots, or internal tools that build GitPython calls from untrusted integration settings or job definitions (yaml, json, etc configs )What the attacker needs to control:A value that becomes `upload_pack` or `receive_pack` in the kwargs passed to `Repo.clone_from()`, `Remote.fetch()`, `Remote.pull()`, or `Remote.push()`From a severity perspective, this could lead toTheft of SSH keys, deploy credentials, API tokens, or cloud credentials available to the processModification of repositories, build outputs, or release artifactsLateral movement from CI/CD workers or automation hostsFull compromise of the worker or service process handling repository operationsThe highest-risk environments are network-reachable services and automation systems that expose these GitPython kwargs across a trust boundary while relying on the default unsafe-option guard for protection.
CVSS v3.1: 8.8