NIST deprecates RSA-2048 from 2030. Find every one of them before attackers do.
🐍
🐍 PyPI
Not in CISA KEV
HIGH severity

GitPython: git-config OPTION-name injection via =/#/whitespace bypasses name validator, enabling forged core.sshCommand/hooksPath (RCE)GHSA-jm78-9fvv-mhgr

HIGHFix: gitpython-developers/GitPython#2204

GHSA-jm78-9fvv-mhgr is a high-severity (CVSS 8.8) CWE-74 vulnerability in gitpython. A fix is available for gitpython — see the affected versions and patch details below.

Also known asCVE-2026-76221PYSEC-2026-3783
Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Nov 5, 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 GHSA-jm78-9fvv-mhgr.

EPSS Exploitation Probability

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

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

How urgent is this, really

Where this sits among everything scored

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

GitPython's config-name validator only neutralizes CR/LF/NUL for the "option" label; it does not reject =, #, ;, [, ], or whitespace in an option name. write_section writes the option name verbatim into the config file, so an option name such as sshCommand = touch <cmd> # is written as \tsshCommand = touch <cmd> # = <value>, which git parses as core.sshCommand = touch <cmd> (the trailing # comments out the intended value). This forges arbitrary config directives (core.sshCommand, core.hooksPath, alias.*) → RCE on the next git operation. This is a distinct field (option name, not section name) and distinct character class (=/#/space, not newline/bracket) from GHSA-3rp5-jjmw-4wv2 (section-name bracket injection) and GHSA-mv93-w799-cj2w / GHSA-v87r-6q3f-2j67 (newline injection).

Root Cause

_assure_config_name_safe(name, label) (git/config.py:897) applies the bracket/quote state machine ONLY when label == "section"; for the "option" label it falls through with just the UNSAFE_CONFIG_CHARS_RE = [\r\n\x00] regex. write_section then writes the option name verbatim into "\t%s = %s\n" (config.py:702).

Impact

Arbitrary git-config directive injection → remote code execution via core.sshCommand (fires on any ssh git operation, no staged file needed) or core.hooksPath (with a staged hook). Requires the embedding application to forward a caller-influenced OPTION NAME into the config writer (name-control model, the same name-control model accepted by the related published advisories GHSA-3rp5-jjmw-4wv2 and GHSA-mv93-w799-cj2w). Default configuration.

Proof of Concept

with repo.config_writer() as cw:
    cw.set_value("core", "sshCommand = touch /tmp/RCE #", "x")
# git config --get core.sshCommand  ->  touch /tmp/RCE

Attack Chain

  1. Entry: app calls config writer with attacker-controlled OPTION name: set_value("core", "sshCommand = touch /tmp/RCE #", "x").
  2. Check: _assure_config_name_safe(option, "option") @ config.py. Guard: regex matches only [\r\n\x00]; bracket/quote state machine is gated on label=="section". Bypass proof: =,#,space pass → no ValueError.
  3. Sink: write_section writes "\tsshCommand = touch /tmp/RCE # = x\n" (config.py:702).
  4. Impact: git parses core.sshCommand=touch /tmp/RCE → arbitrary code execution on next git op.

Bypass Evidence

Independently reproduced (gate harness): set_value('core','sshCommand = touch <RCE> #','x') → no ValueError; file line sshCommand = touch <RCE> # = x; git config --get core.sshCommand → touch <RCE> (rc=0). Also verified core.hooksPath via both GitConfigParser and repo.config_writer(). Fix-commit read: bracket/quote checks are inside if label == "section"; the "option" label is not covered.

Affected Versions

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

Suggested Fix

Apply the section-name safety checks (reject =, #, ;, [, ], whitespace) to the "option" label as well, or validate the fully-rendered config line after substitution.


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 GHSA-jm78-9fvv-mhgr 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 option-name validator fails to neutralize equals signs, hash symbols, and whitespace in option names, letting an attacker who controls option names forge arbitrary git-config directives (e.g. `sshCommand = touch /tmp/RCE #`) that execute arbitrary commands via core.sshCommand or core.hooksPath on the next…

Workaround published by Red Hat
Do not pass untrusted or attacker-influenced git option names to GitPython. Upgrade to GitPython 3.1.58 or later, where option-name (config) injection is fixed.
Source: Red Hat security advisory for GHSA-jm78-9fvv-mhgr (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 Ansible Automation Platform 2.7ansible-automation-platform-27/hub-rhel9:1791254555RHSA-2026:79378
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

Frequently Asked Questions

## Summary GitPython's config-name validator only neutralizes CR/LF/NUL for the `"option"` label; it does not reject `=`, `#`, `;`, `[`, `]`, or whitespace in an **option name**. `write_section` writes the option name verbatim into the config file, so an option name such as `sshCommand = touch <cmd> #` is written as `\tsshCommand = touch <cmd> # = <value>`, which git parses as `core.sshCommand = touch <cmd>` (the trailing `#` comments out the intended value). This forges arbitrary config directives (`core.sshCommand`, `core.hooksPath`, `alias.*`) → RCE on the next git operation. This is a dist
O3 Security · Impact-Aware SCA

Is GHSA-jm78-9fvv-mhgr in your dependencies?

Find it across PyPI, including transitive dependencies.

GitPython: git-config OPTION-name injection via…