GHSA-w8jc-g24h-crhw: High severity pip/gitpython vulnerability

Published Oct 27, 2026
·
Updated

Summary

GitPython has spent 2022-2026 rolling out two reusable guards method-by-method: Git.checkunsafeprotocols(url) (raises UnsafeProtocolError for <transport>:: remote-helper URLs - CVE-2022-24439) and Git.checkunsafeoptions(...) (raises UnsafeOptionError for denylisted option spellings - CVE-2023-40267, CVE-2026-42215, CVE-2026-67323). Three wrapper methods that build a git argv from caller-controlled values still have neither:

1. Git.lsremote (git/cmd.py:1128-1143) - checks options (:1139-1141) but forwards the URL positional unchecked; no allowunsafeprotocols parameter exists. The same URL through clonefrom raises UnsafeProtocolError. 2. Repo.mergebase (git/repo/base.py:895-936) - forwards kwargs/rev to self.git.mergebase with no guard; guarded sibling itercommits sits 12 lines up. Its exception handler additionally swallows every non-128 GitCommandError into [], masking the injection. 3. IndexFile.move (git/index/base.py:1092-1168) - forwards kwargs to git mv twice (:1147, :1167); guarded sibling remove() is 23 lines above.

Verified unfixed on main @ a54d159 (2026-09-21), post-dating latest release 3.1.62 (2026-09-07) - all three sites re-verified today.

Impact

Site 1 (lsremote) - RCE conditional on the victim git transport policy. The common 'probe first, then clone' pattern (Git(...).lsremote(attackerurl)) with an ext::sh -c ... URL executes arbitrary commands when the victim git permits the ext transport: dynamically verified with protocol.ext.allow=always (marker executed). git >= 2.38.1 stock config refuses the transport (fatal: transport 'ext' not allowed, rc 128) - GitPython adds no defense-in-depth and surfaces a bare GitCommandError. Environments on git < 2.38.1 are exposed with stock config - the exact population CVE-2022-24439 was scored against.

Sites 2/3 - latent argument-injection surface: caller kwargs flow 1:1 into the git argv before operands and -- (cmd.py:1850 optargs + extargs), and executekwargs (incl. shell=True/env - the CVE-2023-40267 Windows mechanism) passes through unguarded. Today git merge-base/git mv expose no exec option, so we claim the missing-guard class (vendor-settled by CVE-2026-67323, which bundled archive/lsremote/itercommits/blame in one advisory), not direct RCE.

Dynamic verification (today; GitPython main @ a54d159, git 2.55.0, Linux)

| # | Call | Result | |---|---|---| | T1 | repo.git.lsremote('ext::/tmp/gptouch.sh'), stock config | git refuses (rc 128); no UnsafeProtocolError from GitPython | | T1b | same + victim config protocol.ext.allow=always | marker created - arbitrary command executed | | T2 | repo.git.lsremote('.', uploadpack=...) | blocked by cmd.py:1141 (options-side fixed - protocol-side is the residual gap) | | T3 | repo.mergebase('main','side', uploadpack=...) | not blocked; argv git merge-base --upload-pack=... main side; rc 129 silently converted to [] | | T4 | repo.index.move(['f1','f2'], output=...) | not blocked; option reaches git mv (rc 129) |

Coverage matrix (main @ a54d159)

checkunsafeprotocols: 7 call sites (clone, archive, seturl, create, fetch, pull, push) - none on lsremote. checkunsafeoptions: 24 call sites incl. lsremote, itercommits, IndexFile.remove - absent on mergebase and move.

Precedents (same repo, same guard family)

- CVE-2022-24439 / GHSA-hcpj-qp55-gfph (critical): checkunsafeprotocols on the clone path - Site 1 is the same ext:: primitive on a sibling API. - CVE-2023-40267 / GHSA-pr76-5cm5-w9cj (critical, 'incomplete fix for CVE-2022-24439'): checkunsafeoptions - unguarded kwargs to argv treated as RCE (shell=True on Windows). - CVE-2026-42215 / GHSA-rpm5-65cw-6hj4 (high, fixed 3.1.47): underscored-spelling bypass - rollout still active in 2026. - CVE-2026-67323 / GHSA-956x-8gvw-wg5v (high, 8.4, fixed 3.1.51): added checkunsafeoptions to archive/lsremote/itercommits/blame; its PoC is literally repo.git.lsremote('.', uploadpack=...). Establishes that a wrapper missing the check is itself a vulnerability. This report is the residual gap of that rollout: lsremote got options but not protocols; mergebase/move got neither.

Recommended fix (existing helpers, 1-3 lines per site)

1. Git.lsremote: if not allowunsafeprotocols: self.checkunsafeprotocols(args[0]) + new allowunsafeprotocols: bool = False (the clone pattern, base.py:1536-1538). 2. Repo.mergebase: checkunsafeoptions(Git.optioncandidates(list(rev), kwargs), unsafeoptions=self.unsafegitrevisionoptions) (the itercommits pattern); stop masking non-128 statuses. 3. IndexFile.move: the remove() pattern with unsafegitpathspecfromfileoptions.

One advisory, three affected methods, severity anchored on Site 1 - mirroring CVE-2026-67323's bundling.

Affected Software

1 affected componentFixes available
pip/gitpython<=3.1.62
3.2.0

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade pip/GitPython to a version that resolves this vulnerability.

    Fixed in 3.2.0
  2. Upgrade

    Upgrade GitPython to a version that resolves this vulnerability.

    Fixed in 3.1.47
  3. Upgrade

    Upgrade GitPython to a version that resolves this vulnerability.

    Fixed in 3.1.51
  4. Compensating control

    Update Git.ls_remote to add an allow_unsafe_protocols: bool = False parameter and call Git.check_unsafe_protocols(args[0]) when allow_unsafe_protocols is false, matching the _clone pattern.

  5. Compensating control

    Update IndexFile.move to apply the remove() guard pattern, including unsafe_git_pathspec_from_file_options, before forwarding kwargs to git mv.

  6. Compensating control

    Update Repo.merge_base to call check_unsafe_options(Git._option_candidates(list(rev), kwargs), unsafe_options=self.unsafe_git_revision_options) before invoking git merge-base.

  7. Operational

    Stop converting non-128 GitCommandError statuses to an empty list in the affected command-handling path, so errors such as rc 129 are surfaced instead of masked.

Event History

Oct 27, 2026
Advisory Published
via GitHub·03:26 PM
Data Sourced
via GitHub·03:26 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Which application code paths need review first?

Review uses of Git.ls_remote where the remote URL can be influenced externally, Repo.merge_base calls that pass externally influenced revisions or keyword arguments, and IndexFile.move calls with externally influenced keyword arguments. These wrappers build git command arguments without the reusable unsafe-protocol or unsafe-option protections described for other methods.

2

What does an attacker need to control to attempt exploitation?

An attacker needs influence over values passed into one of the affected wrappers: the URL passed to Git.ls_remote, revisions or keyword arguments passed to Repo.merge_base, or keyword arguments passed to IndexFile.move. The supplied vector indicates network access, no required privileges, high attack complexity, and required user interaction.

3

How can we identify potentially affected deployments?

Search application code for calls to Git.ls_remote, Repo.merge_base, and IndexFile.move, then determine whether their URL, revision, or keyword-argument inputs can originate from users, repositories, build metadata, or other untrusted sources. Repo.merge_base may be harder to spot during testing because it converts non-128 GitCommandError exceptions into an empty list.

4

Is there a safe alternative indicated for remote URLs?

The description identifies clone_from as a contrasting path: the same URL passed through clone_from raises UnsafeProtocolError. Git.ls_remote does not expose an allow_unsafe_protocols parameter and forwards its URL positional argument without the corresponding protocol check.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203