Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐍 PyPI
Not in CISA KEV

CVE-2026-76220 — gitpython

Fix: gitpython-developers/GitPython#2204

CVE-2026-76220 is a CWE-88 vulnerability in gitpython. A fix is available for gitpython — see the affected versions and patch details below.

GitPython before 3.1.58 Command Execution via split_single_char_options

Also known asGHSA-wvpp-8hx9-p66jPYSEC-2026-3843
Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Oct 3, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

No confirmed exploitation observed yet

  • A successful exploit gives an attacker total control of the affected component, not partial access.
  • CISA’s own triage has not observed active exploitation or public proof-of-concept code for this CVE as of its last assessment.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-76220.

EPSS Exploitation Probability

via FIRST.org ↗
0.9%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs59th percentile — riskier than 59% of all scored CVEsHighest risk

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

Real-World Exposure

1 pkg affected
🐍gitpython

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.

Description

Summary

The check_unsafe_options guard can be bypassed on every guarded method (clone/clone_from, fetch/pull/push, ls_remote, iter_commits, blame, archive) by combining a single-character kwarg with split_single_char_options=False. The guard's candidate list omits the smuggled option, but transform_kwarg emits a JOINED -n<value> argv token that git parses as --upload-pack=<cmd>, yielding arbitrary command execution at the default allow_unsafe_options=False. This is an incomplete-fix bypass of commit e8d0fbf7 (the fix for GHSA-r9mr-m37c-5fr3), which only emits value-derived candidates when split_single_char_options is True.

Root Cause

_option_candidates derives value-token candidates only under if len(key)==1 and split_single_char_options: (cmd.py:1048, added by e8d0fbf7). With split_single_char_options=False, _option_candidates([], {"n":"utouch <cmd>;git-upload-pack"}) returns only ['-n'] (not on the denylist), so the guard passes. But transform_kwarg('n', value, split_single_char_options=False) emits the JOINED token -nutouch <cmd>;git-upload-pack (cmd.py:1631). git clusters value-less short flags then parses -u<cmd> = --upload-pack=<cmd> → command execution. The hardened guard WOULD block the joined token if it saw it — the flaw is it never receives it.

Impact

Arbitrary OS command execution as the host process (via --upload-pack) at default allow_unsafe_options=False, affecting all guarded methods that forward kwargs. Precondition: the app forwards a user-controlled kwargs dict containing split_single_char_options=False plus a single-char key (same user-dict-forwarding model GHSA-r9mr-m37c-5fr3 accepts).

Proof of Concept

from git import Repo
Repo.clone_from(src, dst,
    n="utouch /tmp/ACE;git-upload-pack",
    split_single_char_options=False)   # /tmp/ACE created -> ACE

Attack Chain

  1. Entry: app forwards user kwargs to Repo.clone_from(url, path, **kwargs): {split_single_char_options: False, n: 'utouch /tmp/ACE;git-upload-pack'}.
  2. Check: check_unsafe_options(_option_candidates([], kwargs), unsafe_git_clone_options). Guard: denylist includes --upload-pack/-u. Bypass proof: _option_candidates yields only ['-n'] (value token skipped because split=False); guard never sees -u.
  3. Sink: transform_kwarg emits joined token (cmd.py:1631). argv (observed): ['git','clone','-v','-nutouch /tmp/ACE;git-upload-pack','--','<src>','<dst>'].
  4. Impact: git clusters -n + -u<cmd> → runs upload-pack command → ACE.

Bypass Evidence

Independently reproduced (gate harness, default allow_unsafe_options=False): the split=False payload created the marker VH05_GATE_ACE (ACE); the clone returned normally (guard bypassed). Control: n='--upload-pack=…' (split default True) → UnsafeOptionError: --upload-pack is not allowed. Fix-commit read: e8d0fbf7 extends candidates only under if len(key)==1 and split_single_char_options: — split=False skips value emission. Also confirmed the earlier clustering-parse fix (commit 56806080) does not cover this because the guard only ever receives ['-n'].

Affected Versions

GitPython <= 3.1.57 (code present verbatim on the latest release tag).

Suggested Fix

Make _option_candidates emit value-derived candidates regardless of split_single_char_options (i.e. also for the joined -n<value> form), OR run check_unsafe_options over the fully-transformed argv rather than the reconstructed name-only candidate list.


Reported by zx (Jace) — GitHub: @manus-use

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐍PyPIgitpythonall versions3.1.58pip install --upgrade 'gitpython==3.1.58'

Affected Products

1 product · 1 configurations
Application
gitpythongitpython_project
< 3.1.58
range

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for gitpython, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update gitpython to 3.1.58 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-76220 is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

Fixing This On Your OS

If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.

Red HatImportant

GitPython's check_unsafe_options guard can be bypassed by combining a single-character keyword argument with split_single_char_options=False, letting an attacker who supplies a crafted kwargs dictionary to guarded methods such as clone_from emit a joined token parsed as `--upload-pack` and achieve arbitrary OS command…

Workaround published by Red Hat
Do not pass untrusted or attacker-influenced keyword arguments to GitPython's guarded methods such as clone_from, and do not set split_single_char_options=False on untrusted input. Upgrade to GitPython 3.1.58 or later, where the check_unsafe_options bypass is fixed.
Source: Red Hat security advisory for CVE-2026-76220 (CC BY 4.0)
ProductFixed inAdvisory
Red Hat Satellite 6.19 for RHEL 9python3.12-gitpython-0:3.1.59-1.el9pcRHSA-2026:63385
Red Hat Ansible Automation Platform 2.5ansible-automation-platform-25/controller-rhel8:1789607021RHSA-2026:71210
Red Hat Ansible Automation Platform 2.6ansible-automation-platform-26/controller-rhel9:1789673739RHSA-2026:71179
Red Hat Ansible Automation Platform 2.7ansible-automation-platform-27/controller-rhel9:1789580684RHSA-2026:71177
Red Hat Satellite 6.18satellite/iop-vmaas-rhel9:1789611858RHSA-2026:68764
Red Hat Satellite 6.18satellite/iop-vulnerability-engine-rhel9:1789637082RHSA-2026:68771
Red Hat Satellite 6.19satellite/iop-vulnerability-engine-rhel9:1789607605RHSA-2026:68776
Red Hat Satellite 6.19satellite/iop-vmaas-rhel9:1789611998RHSA-2026:68780

Frequently Asked Questions

## Summary The `check_unsafe_options` guard can be bypassed on every guarded method (clone/clone_from, fetch/pull/push, ls_remote, iter_commits, blame, archive) by combining a single-character kwarg with `split_single_char_options=False`. The guard's candidate list omits the smuggled option, but `transform_kwarg` emits a JOINED `-n<value>` argv token that git parses as `--upload-pack=<cmd>`, yielding arbitrary command execution at the default `allow_unsafe_options=False`. This is an incomplete-fix bypass of commit `e8d0fbf7` (the fix for GHSA-r9mr-m37c-5fr3), which only emits value-derived can
O3 Security · Impact-Aware SCA

Is CVE-2026-76220 in your dependencies?

Find it across PyPI, including transitive dependencies.

CVE-2026-76220: gitpython — Fixed in 3.1.58 | O3 Security