chore: update dependency gitpython to v3.1.52 [security]#95
Open
renovate[bot] wants to merge 1 commit into
Open
chore: update dependency gitpython to v3.1.52 [security]#95renovate[bot] wants to merge 1 commit into
renovate[bot] wants to merge 1 commit into
Conversation
renovate
Bot
force-pushed
the
renovate/pypi-gitpython-vulnerability
branch
from
January 14, 2025 18:34
d27723b to
4a31131
Compare
renovate
Bot
force-pushed
the
renovate/pypi-gitpython-vulnerability
branch
from
August 10, 2025 14:42
4a31131 to
c2ac898
Compare
renovate
Bot
force-pushed
the
renovate/pypi-gitpython-vulnerability
branch
from
February 2, 2026 20:12
c2ac898 to
d7c546c
Compare
renovate
Bot
force-pushed
the
renovate/pypi-gitpython-vulnerability
branch
2 times, most recently
from
March 30, 2026 18:31
d7c546c to
e095fbc
Compare
renovate
Bot
force-pushed
the
renovate/pypi-gitpython-vulnerability
branch
from
April 26, 2026 01:30
e095fbc to
7e11630
Compare
renovate
Bot
force-pushed
the
renovate/pypi-gitpython-vulnerability
branch
3 times, most recently
from
April 30, 2026 16:04
0ceb1b9 to
6f2989c
Compare
renovate
Bot
force-pushed
the
renovate/pypi-gitpython-vulnerability
branch
from
May 8, 2026 09:09
6f2989c to
1fc73bc
Compare
renovate
Bot
force-pushed
the
renovate/pypi-gitpython-vulnerability
branch
from
July 21, 2026 03:46
1fc73bc to
4c17148
Compare
renovate
Bot
force-pushed
the
renovate/pypi-gitpython-vulnerability
branch
from
July 24, 2026 01:31
4c17148 to
7d3ea05
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
3.1.27→3.1.52GitPython vulnerable to Remote Code Execution due to improper user input validation
CVE-2022-24439 / GHSA-hcpj-qp55-gfph
More information
Details
All versions of package gitpython are 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.
Severity
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
GitPython vulnerable to remote code execution due to insufficient sanitization of input arguments
CVE-2023-40267 / GHSA-pr76-5cm5-w9cj
More information
Details
GitPython before 3.1.32 does not block insecure non-multi options in
cloneandclone_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 for CVE-2022-24439.Severity
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
GitPython untrusted search path on Windows systems leading to arbitrary code execution
CVE-2023-40590 / GHSA-wfm5-v35h-vwf4
More information
Details
Summary
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
gitcommand, if a user runs GitPython from a repo has agit.exeorgitexecutable, that program will be run instead of the one in the user'sPATH.Details
This is more of a problem on how Python interacts with Windows systems, Linux and any other OS aren't affected by this. But probably people using GitPython usually run it from the CWD of a repo.
The execution of the
gitcommand happens inhttps://github.com/gitpython-developers/GitPython/blob/1c8310d7cae144f74a671cbe17e51f63a830adbf/git/cmd.py#L277
https://github.com/gitpython-developers/GitPython/blob/1c8310d7cae144f74a671cbe17e51f63a830adbf/git/cmd.py#L983-L996
And there are other commands executed that should probably be aware of this problem.
PoC
On a Windows system, create a
git.exeorgitexecutable in any directory, and import or run GitPython from that directoryThe git executable from the current directory will be run.
Impact
An attacker can trick a user to download a repository with a malicious
gitexecutable, if the user runs/imports GitPython from that directory, it allows the attacker to run any arbitrary commands.Possible solutions
C:\\Program Files\\Git\\cmd\\git.EXE(default git path installation).GIT_PYTHON_GIT_EXECUTABLEenvironment variable on Windows systems.GIT_PYTHON_GIT_EXECUTABLEenv var to an absolute path.PATHenvironment variable (suggested by @Byron)Severity
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Untrusted search path under some conditions on Windows allows arbitrary code execution
CVE-2024-22190 / GHSA-2mqj-m65w-jghx
More information
Details
Summary
This issue exists because of an incomplete fix for CVE-2023-40590. On Windows, GitPython uses an untrusted search path if it uses a shell to run
git, as well as when it runsbash.exeto interpret hooks. If either of those features are used on Windows, a maliciousgit.exeorbash.exemay be run from an untrusted repository.Details
Although GitPython often avoids executing programs found in an untrusted search path since 3.1.33, two situations remain where this still occurs. Either can allow arbitrary code execution under some circumstances.
When a shell is used
GitPython can be told to run
gitcommands through a shell rather than as direct subprocesses, by passingshell=Trueto any method that accepts it, or by both settingGit.USE_SHELL = Trueand not passingshell=False. Then the Windowscmd.exeshell process performs the path search, and GitPython does not prevent that shell from finding and runninggitin the current directory.When GitPython runs
gitdirectly rather than through a shell, the GitPython process performs the path search, and currently omits the current directory by settingNoDefaultCurrentDirectoryInExePathin its own environment during thePopencall. Although thecmd.exeshell will honor this environment variable when present, GitPython does not currently pass it into the shell subprocess's environment.Furthermore, because GitPython sets the subprocess CWD to the root of a repository's working tree, using a shell will run a malicious
git.exein an untrusted repository even if GitPython itself is run from a trusted location.This also applies if
Git.executeis called directly withshell=True(or afterGit.USE_SHELL = True) to run any command.When hook scripts are run
On Windows, GitPython uses
bash.exeto run hooks that appear to be scripts. However, unlike when runninggit, no steps are taken to avoid finding and runningbash.exein the current directory.This allows the author of an untrusted fork or branch to cause a malicious
bash.exeto be run in some otherwise safe workflows. An example of such a scenario is if the user installs a trusted hook while on a trusted branch, then switches to an untrusted feature branch (possibly from a fork) to review proposed changes. If the untrusted feature branch contains a maliciousbash.exeand the user's current working directory is the working tree, and the user performs an action that runs the hook, then although the hook itself is uncorrupted, it runs with the maliciousbash.exe.Note that, while
bash.exeis a shell, this is a separate scenario from whengitis run using the unrelated Windowscmd.exeshell.PoC
On Windows, create a
git.exefile in a repository. Then create aRepoobject, and call any method through it (directly or indirectly) that supports theshellkeyword argument withshell=True:The
git.exeexecutable in the repository directory will be run.Or use no
Repoobject, but do it from the location with thegit.exe:The
git.exeexecutable in the current directory will be run.For the scenario with hooks, install a hook in a repository, create a
bash.exefile in the current directory, and perform an operation that causes GitPython to attempt to run the hook:The
bash.exeexecutable in the current directory will be run.Impact
The greatest impact is probably in applications that set
Git.USE_SHELL = Truefor historical reasons. (Undesired console windows had, in the past, been created in some kinds of applications, when it was not used.) Such an application may be vulnerable to arbitrary code execution from a malicious repository, even with no other exacerbating conditions. This is to say that, if a shell is used to rungit, the full effect of CVE-2023-40590 is still present. Furthermore, as noted above, running the application itself from a trusted directory is not a sufficient mitigation.An application that does not direct GitPython to use a shell to run
gitsubprocesses thus avoids most of the risk. However, there is no such straightforward way to prevent GitPython from runningbash.exeto interpret hooks. So while the conditions needed for that to be exploited are more involved, it may be harder to mitigate decisively prior to patching.Possible solutions
A straightforward approach would be to address each bug directly:
NoDefaultCurrentDirectoryInExePathinto the subprocess environment, because in that scenario the subprocess is thecmd.exeshell that itself performs the path search.NoDefaultCurrentDirectoryInExePathin the GitPython process environment during thePopencall made to run hooks with abash.exesubprocess.These need only be done on Windows.
Severity
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
GitPython blind local file inclusion
CVE-2023-41040 / GHSA-cwvm-v4w8-q58c
More information
Details
Summary
In order to resolve some git references, GitPython reads files from the
.gitdirectory, 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.gitdirectory. This allows an attacker to make GitPython read any file from the system.Details
This vulnerability is present in
https://github.com/gitpython-developers/GitPython/blob/1c8310d7cae144f74a671cbe17e51f63a830adbf/git/refs/symbolic.py#L174-L175
That code joins the base directory with a user given string without checking if the final path is located outside the base directory.
I was able to exploit it from three places, but there may be more code paths that lead to it:
https://github.com/gitpython-developers/GitPython/blob/1c8310d7cae144f74a671cbe17e51f63a830adbf/git/repo/base.py#L605
https://github.com/gitpython-developers/GitPython/blob/1c8310d7cae144f74a671cbe17e51f63a830adbf/git/repo/base.py#L620
https://github.com/gitpython-developers/GitPython/blob/1c8310d7cae144f74a671cbe17e51f63a830adbf/git/index/base.py#L1353
PoC
Running GitPython within any repo should work, here is an example with the GitPython repo.
Impact
I wasn't able to show the contents of the files (that's why "blind" local file inclusion), depending on how GitPython is being used, this can be used by an attacker for something inoffensive as checking if a file exits, or cause a DoS by making GitPython read a big/infinite file (like
/dev/randomon Linux systems).Possible solutions
A solution would be to check that the final path isn't located outside the
repodirpath (maybe even after resolving symlinks). Maybe there could be other checks in place to make sure that the reference names are valid.Severity
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
GitPython: Unsafe option check validates multi_options before shlex.split transformation
CVE-2026-42284 / GHSA-x2qx-6953-8485
More information
Details
Summary
_clone()validatesmulti_optionsas the original list, then executesshlex.split(" ".join(multi_options)). A string like"--branch main --config core.hooksPath=/x"passes validation (starts with--branch), but after split becomes["--branch", "main", "--config", "core.hooksPath=/x"]. Git applies the config and executes attacker hooks during clone.Details
The vulnerable code is in
git/repo/base.pyline 1383:Then validation runs on the original list at line 1390:
Then execution uses the transformed result at line 1392:
The check at
git/cmd.pyline 959 usesstartswith:"--branch main --config ..."does not start with"--config", so it passes. Aftershlex.split,"--config"becomes its own token and reaches git.Also affects
Submodule.update()viaclone_multi_options.PoC
Output:
Impact
Any application passing user input to
multi_optionsinclone_from(),clone(), orSubmodule.update()is vulnerable. Attacker embeds--config core.hooksPath=<dir>inside a string starting with a safe option. Check does not block it. Git executes attacker code. Same class as CVE-2023-40267.Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:HReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
GitPython reference APIs has a path traversal vulnerability that allows arbitrary file write and delete outside the repository
CVE-2026-44243 / GHSA-7545-fcxq-7j24
More information
Details
🧾 Summary
A vulnerability in GitPython allows attackers who can supply a crafted reference path to an application using GitPython to write, overwrite, move, or delete files outside the repository’s
.gitdirectory via insufficient validation of reference paths in reference creation, rename, and delete operations.📦 Affected Versions
<= 3.1.46and currentmain(3.1.47in local checkout)🧠 Details
Vulnerability Type
Path Traversal leading to Arbitrary File Write and Arbitrary File Deletion
Root Cause
Reference paths are validated when they are resolved for reading, but are not consistently validated before filesystem write, rename, and delete operations.
SymbolicReference._check_ref_name_valid()rejects traversal sequences such as.., butSymbolicReference.create,Reference.create,SymbolicReference.set_reference,SymbolicReference.rename, andSymbolicReference.deletestill construct filesystem paths from attacker-controlled ref names without enforcing repository boundaries.Affected Code
Attack Vector
Local attack through application-controlled input passed into GitPython reference APIs
Authentication Required
None at the library boundary. In practice, exploitation requires the ability to influence ref names supplied by the consuming application.
🧪 Proof of Concept
Setup
Exploit
Result
💥 Impact
What can an attacker do?
Security Impact
Who is affected?
🛠️ Mitigation / Fix
Recommended Fix
Severity
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N/E:PReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
GitPython: Newline injection in config_writer().set_value() enables RCE via core.hooksPath
CVE-2026-44244 / GHSA-v87r-6q3f-2j67
More information
Details
GitConfigParser.set_value()passes values to Python'sconfigparserwithout validating for newlines. GitPython's own_write()converts embedded newlines into indented continuation lines (e.g.\nbecomes\n\t), but Git still accepts an indented[core]stanza as a section header — so the injectedcore.hooksPathbecomes 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 own writer converts embedded newlines into indented continuation lines, but Git still accepts an indented
[core]stanza as a section header, so the injectedcore.hooksPathbecomes effective configuration.This was found while auditing MLRun's
project.push()method, which passesauthor_nameandauthor_emaildirectly toconfig_writer().set_value()with no sanitization. Both parameters cross a trust boundary — they are caller-supplied API inputs that end up in.git/config.PoC (standalone, no MLRun required):
Tested on GitPython 3.1.46, git 2.39+.
Impact: This is persistent repo config poisoning. Any user who can supply
author_nameorauthor_emailto an application callingconfig_writer().set_value()can redirect Git hook execution to an arbitrary path. In a multi-user or hosted environment (e.g. a shared MLRun server where multiple users push to the same repositories), one user can poison the.git/configof a shared repo and have their hooks run in the context of every subsequent Git operation by any user. On single-user deployments, the impact depends on whether the application later invokes Git hooks automatically.Remediation:
set_value()should raise on CR, LF, or NUL in values rather than silently pass them through:Rejecting is safer than stripping — a stripped newline might indicate the caller is passing unsanitized input at a higher level, and silent normalization masks that.
Affected wherever
config_writer().set_value(section, key, user_input)is called with external input.** GitPython is a dependency of DVC, MLflow, Kedro, and others — worth auditing theirset_value()call sites for externally influenced inputs.Severity
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
GitPython: Newline injection in config_writer() section parameter bypasses CVE-2026-42215 patch, enabling RCE via core.hooksPath
GHSA-mv93-w799-cj2w
More information
Details
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 3.1.49 (latest patched version)
_write() formats section headers as "[%s]\n" % name. When section = "user]\n[core", this writes [user]\n[core]\n — two valid section headers — into .git/config.
PoC
Impact
Same attack outcome as CVE-2026-42215 (RCE via core.hooksPath injection). The patch is incomplete — only value is validated while section and option remain injectable.
Severity
CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:HReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
GitPython: Command Injection via git long-option prefix abbreviation bypass of CVE-2026-42215 blocklist
GHSA-2f96-g7mh-g2hx
More information
Details
Command injection via long-option prefix abbreviation bypassing
check_unsafe_options(incomplete fix of CVE-2026-42215 / GHSA-rpm5-65cw-6hj4)Component: gitpython-developers/GitPython (PyPI: GitPython)
Affected: all versions carrying the 3.1.47 blocklist fix, through current
main(verified at commit20c5e275,3.1.50-42)CWE: CWE-184 (Incomplete List of Disallowed Inputs) → CWE-78 (OS Command Injection)
Severity: inherits the parent CVE-2026-42215 surface; estimated High, ~8.8 (
AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H) — final scoring deferred to maintainer/CNA, mirroring the parent.Reporter: hackkim
Summary
The 3.1.47 fix for CVE-2026-42215 blocks dangerous git options (
--upload-pack,--config,-c,-ufor clone;--upload-packfor fetch/pull;--receive-pack,--execfor push) so callers cannot reach command-executing options unless they passallow_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 (--upload-p,--upload-pa,--upload-pacall resolve to--upload-pack). So a kwarg key likeupload_pcanonicalizes toupload-p, misses the blocklist dict, and is emitted to git as--upload-p=<value>→ executed as--upload-pack=<value>→ command injection, in the defaultallow_unsafe_options=Falseconfiguration.The asymmetry (root cause)
The guard normalizes only
_→-and does exact dict membership. Git's CLI parser accepts a broader grammar (prefix abbreviation) than the guard models, so abbreviated keys slip through and reach git as the blocked option.Affected code (commit
20c5e275)git/cmd.py:948-960_canonicalize_option_namegit/cmd.py:963-974check_unsafe_optionsgit/cmd.py:1511transform_kwarg--<dashify(name)>=<value>to the CLIgit/repo/base.py:1411,1413git/remote.py:1074,1128,1201Bypass keys (verified)
upload_p,upload_pac--upload-packreceive_p--receive-packexe--execconf,confi--configMinimal PoC
Self-contained, no network egress (a local bare repo acts as the "remote"). Tested on current
main(git 2.50.1):Equivalent at the shell:
git clone --upload-p=/tmp/evil.sh src outrunsevil.sh.Confirmed behavior:
upload_pack(exact) → blocked;upload_p(abbrev) → passes guard, reaches git, executes. The fix works for the form it models but not the abbreviated form.allow_unsafe_options=Trueopt-out behaves as documented (out of scope).Honest scope note
Like the parent CVE, exploitation requires a host application that flows attacker-controlled kwarg keys into a GitPython clone/fetch/pull/push. Where the host passes only fixed/validated keys, this is not reachable — the vulnerability is in the library's documented defense-in-depth control (
allow_unsafe_options=False), which this variant defeats.On the
--configfamily:confbypasses the option blocklist, but weaponizing--config protocol.ext.allow=alwaysvia anext::URL is independently blocked by GitPython's protocol allowlist (allow_unsafe_protocols=False). The directly weaponizable family isupload-pack/receive-pack/exec. Reported transparently — not claiming Critical.Suggested remediation (any one)
startswithon the blocked canonical name, afterdashify).--end-of-optionsor invoke git in a way that disables long-option abbreviation.Remediation should also cover the
-c/--configfamily abbreviations, even though theext::route is currently gated by the protocol allowlist.Severity
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
GitPython: command injection via unguarded Git options in
Repo.archive(),git.ls_remote(), and arbitrary file overwrite viaRepo.iter_commits()/Repo.blame()GHSA-956x-8gvw-wg5v
More information
Details
Summary
GitPython spawns the real
gitbinary 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 withGit.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 thegitargv have no guard at all:Repo.archive(ostream, treeish=None, prefix=None, **kwargs)forwards**kwargsverbatim intogit archive. An attacker-influenced options mapping such as{"remote": ".", "exec": "<cmd>"}becomesgit archive --remote=. --exec=<cmd> -- <treeish>, andgit archive --remote=<local repo>invokesgit-upload-archivewhose path is overridden by--exec→ arbitrary command execution under default Git configuration (noprotocol.ext.allowneeded).repo.git.ls_remote(<url>, upload_pack="<cmd>")(and the dynamic-command builder generally) turns theupload_packkwarg into--upload-pack=<cmd>with no guard → arbitrary command execution.Repo.iter_commits(rev)andRepo.blame(rev, file)place the caller'srevvalue into the argv before the--end-of-options separator and apply no leading-dash check. A benign-looking ref value such as--output=/path/to/fileis parsed bygit rev-list/git blameas the--outputoption, which opens and truncates an arbitrary file before Git even validates the revision → arbitrary file clobber (integrity/availability; can destroy keys, configs, lockfiles, or be aimed at files the host later sources).The first two are direct code execution; the third is an arbitrary file-overwrite primitive. All share one root cause: the
check_unsafe_options/ end-of-options discipline that GitPython applies to clone/fetch/pull/push was never extended to these sinks.Details
GitPython explicitly recognises these options as command-execution vectors.
git/remote.py:535:and enforces them via
Git.check_unsafe_options()(git/cmd.py:963):But
check_unsafe_optionsis invoked from only five sites, all network commands:The following sinks call
gitwith caller-controlled options/positionals and are not guarded:1.
Repo.archive— command execution (git/repo/base.py:1623)treeishandpathare correctly placed after--, but**kwargsare converted byGit.transform_kwarg(git/cmd.py:1487) into--<name>=<value>flags and inserted before the--by_call_process, with nocheck_unsafe_options.Repo.archivealready documents user-facing kwargs (format,prefix,path), so forwarding a caller options mapping is an expected usage. Final argv:git archive --remote=<repo>runs the upload-archive helper;--exec=<cmd>overrides the helper path, executing<cmd>on the host. This works with default Git config — it does not rely on theext::transport (which is blocked by default).2.
repo.git.ls_remote(..., upload_pack=...)— command execution (dynamic builder,git/cmd.py:1487)transform_kwargdashifiesupload_pack→--upload-pack=<value>.git ls-remote <local-repo> --upload-pack=<cmd>executes<cmd>. The dynamic builder makes both the flag name and value caller-controlled (repo.git.<anything>(**user_dict)), andls_remotehas nocheck_unsafe_options.This is exactly the underscore-kwarg-vs-hyphen-kwarg gap that CVE-2026-42215 fixed for
fetch/pull/push/clone_from— butls_remoteand the rest of the dynamic surface were left unpatched.3.
Repo.iter_commits/Repo.blame— arbitrary file overwrite (git/objects/commit.py:348,git/repo/base.py:1199)revis placed before--, with no leading-dash check anywhere in the path. A caller passingrev="--output=/path"(a value that looks like an ordinary ref/branch/tag string an app forwards from user input) produces:git rev-list/log/blamehonour--output=<file>, whichopen()s and truncates the file before validating the revision — so the file is destroyed even though Git then errors out on the bad revision.PoC
All three PoCs are self-contained, run against the released GitPython 3.1.50 under default Git configuration, and were executed live (git 2.51.0). Each prints a host-side marker proving the effect.
Install
PoC 1 — command execution via
Repo.archiveVerbatim output:
git config --get protocol.ext.allowreturns nothing (unset = default), confirming no special config is required.PoC 2 — command execution via
git.ls_remote(upload_pack=...)