Every CVE Search/ Get API key

CVE-2026-110855

GitPython before 3.2.0 Environment Variable Disclosure via .gitmodules Submodule Name

7.1 HighFix available

GitPython before 3.2.0 contains an information disclosure vulnerability that allows malicious repositories to expand environment variables via separate_git_dir in Repo._clone(), which omits expand_vars=False when calling Git.polish_url(). Attackers can craft a .gitmodules submodule name containing variable syntax so that clone plus submodule_update exposes secrets in .git/modules directory names and DEBUG logs.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
Passive

What an attacker can affect

Confidentiality
High
Integrity
None
Availability
None

Exploit likelihood

0.29%Up 0.1 points since Oct 15, 2026
90%50%10%1%

What each source reports

CVE List Score used 7.1

GitPython before 3.2.0 Environment Variable Disclosure via .gitmodules Submodule Name

GitPython before 3.2.0 contains an information disclosure vulnerability that allows malicious repositories to expand environment variables via separate_git_dir in Repo._clone(), which omits expand_vars=False when calling Git.polish_url(). Attackers can craft a .gitmodules submodule name containing variable syntax so that clone plus submodule_update exposes secrets in .git/modules directory names and DEBUG logs.

Record
CVE-2026-110855
CVSS 4.0
7.1 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
CVSS 3.1
6.5 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
Weakness
CWE-200
Updated
2026-11-02
EUVDEUVD-2026-101738 7.1

GitPython before 3.2.0 contains an information disclosure vulnerability that allows malicious repositories to expand environment variables via separate_git_dir in Repo._clone(), which omits expand_vars=False when calling Git.polish_url(). Attackers can craft a .gitmodules submodule name containing variable syntax so that clone plus submodule_update exposes secrets in .git/modules directory names and DEBUG logs.

Record
EUVD-2026-101738
CVSS 4.0
7.1 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-cwpg-5qqf-hf36 7.1

GitPython before 3.2.0 contains an information disclosure vulnerability that allows malicious...

GitPython before 3.2.0 contains an information disclosure vulnerability that allows malicious repositories to expand environment variables via separate_git_dir in Repo._clone(), which omits expand_vars=False when calling Git.polish_url(). Attackers can craft a .gitmodules submodule name containing variable syntax so that clone plus submodule_update exposes secrets in .git/modules directory names and DEBUG logs.

Record
GHSA-cwpg-5qqf-hf36
CVSS 4.0
7.1 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
6.5 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
Weakness
CWE-200
Updated
2026-11-02
GitHub AdvisoriesGHSA-fx3j-rwgx-fr94 6.5

GitPython: separate_git_dir leaks env vars via crafted .gitmodules submodule name

Summary

Repo._clone()'s handling of separate_git_dir never disables Git.polish_url()'s environment-variable expansion, unlike every other caller of that helper that handles attacker-influenced data. Since separate_git_dir can be derived from an attacker-controlled .gitmodules submodule name, a completely ordinary clone + submodule_update(init=True, recursive=True) on a malicious repository expands an environment variable of the attacker's choosing and exposes its value both as a persistent on-disk directory name and, whenever DEBUG-level logging is enabled (a common CI/verbose-logging configuration), in a Popen(...) log line that is not redacted the way credential-bearing arguments are.

Root cause / Details

git/repo/base.py's _clone() has:

sep_dir = kwargs.get("separate_git_dir")
if sep_dir:
    kwargs["separate_git_dir"] = Git.polish_url(sep_dir)

This is the only remaining Git.polish_url() call site handling attacker-influenced data that does not pass expand_vars=False (there is one other unguarded call site, clone_path at line 1537, but its input is the caller's own local destination path, not attacker-controlled). The sibling fixes for GHSA-94p4-4cq8-9g67/GHSA-rwj8-pgh3-r573 added expand_vars=False to clone_url (5 lines below this one, in the same function), git/repo/base.py:1599, remote.py:814, and submodule/base.py:686 — this one did not receive it. (submodule/root.py also currently sets expand_vars=False at a related call site, but that was added incidentally by a later, unrelated commit, not as part of these security fixes.) Git.polish_url()'s docstring itself says: "Disable this for values obtained from an untrusted source, such as remote URLs." Its non-Cygwin branch does plain os.path.expandvars() on the entire string, including embedded variables anywhere in an absolute path.

separate_git_dir reaches _clone() from Submodule._clone_repo() (git/objects/submodule/base.py) as module_abspath = osp.join(parent_repo.git_dir, "modules", name), where name is the raw .gitmodules submodule section name — fully attacker-controlled content of a cloned repository. _validated_name() (added by the fix for GHSA-hmq2-w58f-27jc) only rejects names that are absolute, contain a drive letter, or contain .. path components; it does not reject $. _need_gitfile_submodules() is true for git ≥ 1.7.5, i.e. the default path for virtually every real-world installation.

Reproduction (live, against real, unmodified GitPython code, no monkeypatching)

Built a hostile repository with a plain, ordinary git command: git submodule add --name '$GPY_SECRET_MARKER' ../evil_submodule sub. Set an environment variable in the "victim" process (standing in for a real CI secret such as AWS_SECRET_ACCESS_KEY): GPY_SECRET_MARKER=AKIA_TOTALLY_FAKE_BUT_SECRET_LOOKING_VALUE_12345. Then ran the exact ordinary workflow the GHSA-hmq2-w58f-27jc advisory's own PoC also uses:

repo = Repo.clone_from(evil_parent_url, victim_clone_dir)
repo.submodule_update(init=True, recursive=True)

Observed result (ls .git/modules/):

.git/modules/AKIA_TOTALLY_FAKE_BUT_SECRET_LOOKING_VALUE_12345/   (a full git repo: HEAD, config, objects/, refs/, hooks/)

The literal $GPY_SECRET_MARKER-named directory was never created — only the expanded one exists, proving expansion happened before the value reached the git clone --separate-git-dir=... subprocess argument. The persistent, expanded-name directory under .git/modules/ is itself the primary disclosure channel — it survives on disk for as long as the clone does. A second, independent channel: with the git.cmd/git.repo.base loggers at DEBUG level (a common CI/verbose-logging setting, not requiring any special flag), GitPython's own Popen(...) debug log line prints the fully expanded --separate-git-dir=<value> subprocess argument verbatim — remove_password_if_present() only redacts…

Record
GHSA-fx3j-rwgx-fr94
CVSS 3.1
6.5 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
Weakness
CWE-200
Updated
2026-11-02
NVD 7.1

GitPython before 3.2.0 contains an information disclosure vulnerability that allows malicious repositories to expand environment variables via separate_git_dir in Repo._clone(), which omits expand_vars=False when calling Git.polish_url(). Attackers can craft a .gitmodules submodule name containing variable syntax so that clone plus submodule_update exposes secrets in .git/modules directory names and DEBUG logs.

Record
CVE-2026-110855
CVSS 4.0
7.1 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
6.5 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
Weakness
CWE-200
Updated
2026-11-02
OSV 7.1

GitPython before 3.2.0 Environment Variable Disclosure via .gitmodules Submodule Name

GitPython before 3.2.0 contains an information disclosure vulnerability that allows malicious repositories to expand environment variables via separate_git_dir in Repo._clone(), which omits expand_vars=False when calling Git.polish_url(). Attackers can craft a .gitmodules submodule name containing variable syntax so that clone plus submodule_update exposes secrets in .git/modules directory names and DEBUG logs.

Record
CVE-2026-110855
CVSS 4.0
7.1 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
Weakness
CWE-200
Updated
2026-11-03
Show 6 moreShow less
OSVDEBIAN-CVE-2026-110855 7.1

GitPython before 3.2.0 contains an information disclosure vulnerability that allows malicious repositories to expand environment variables via separate_git_dir in Repo._clone(), which omits expand_vars=False when calling Git.polish_url(). Attackers can craft a .gitmodules submodule name containing variable syntax so that clone plus submodule_update exposes secrets in .git/modules directory names and DEBUG logs.

Record
DEBIAN-CVE-2026-110855
CVSS 4.0
7.1 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Updated
2026-11-02
OSVGHSA-fx3j-rwgx-fr94 6.5

GitPython: separate_git_dir leaks env vars via crafted .gitmodules submodule name

Summary

Repo._clone()'s handling of separate_git_dir never disables Git.polish_url()'s environment-variable expansion, unlike every other caller of that helper that handles attacker-influenced data. Since separate_git_dir can be derived from an attacker-controlled .gitmodules submodule name, a completely ordinary clone + submodule_update(init=True, recursive=True) on a malicious repository expands an environment variable of the attacker's choosing and exposes its value both as a persistent on-disk directory name and, whenever DEBUG-level logging is enabled (a common CI/verbose-logging configuration), in a Popen(...) log line that is not redacted the way credential-bearing arguments are.

Root cause / Details

git/repo/base.py's _clone() has:

sep_dir = kwargs.get("separate_git_dir")
if sep_dir:
    kwargs["separate_git_dir"] = Git.polish_url(sep_dir)

This is the only remaining Git.polish_url() call site handling attacker-influenced data that does not pass expand_vars=False (there is one other unguarded call site, clone_path at line 1537, but its input is the caller's own local destination path, not attacker-controlled). The sibling fixes for GHSA-94p4-4cq8-9g67/GHSA-rwj8-pgh3-r573 added expand_vars=False to clone_url (5 lines below this one, in the same function), git/repo/base.py:1599, remote.py:814, and submodule/base.py:686 — this one did not receive it. (submodule/root.py also currently sets expand_vars=False at a related call site, but that was added incidentally by a later, unrelated commit, not as part of these security fixes.) Git.polish_url()'s docstring itself says: "Disable this for values obtained from an untrusted source, such as remote URLs." Its non-Cygwin branch does plain os.path.expandvars() on the entire string, including embedded variables anywhere in an absolute path.

separate_git_dir reaches _clone() from Submodule._clone_repo() (git/objects/submodule/base.py) as module_abspath = osp.join(parent_repo.git_dir, "modules", name), where name is the raw .gitmodules submodule section name — fully attacker-controlled content of a cloned repository. _validated_name() (added by the fix for GHSA-hmq2-w58f-27jc) only rejects names that are absolute, contain a drive letter, or contain .. path components; it does not reject $. _need_gitfile_submodules() is true for git ≥ 1.7.5, i.e. the default path for virtually every real-world installation.

Reproduction (live, against real, unmodified GitPython code, no monkeypatching)

Built a hostile repository with a plain, ordinary git command: git submodule add --name '$GPY_SECRET_MARKER' ../evil_submodule sub. Set an environment variable in the "victim" process (standing in for a real CI secret such as AWS_SECRET_ACCESS_KEY): GPY_SECRET_MARKER=AKIA_TOTALLY_FAKE_BUT_SECRET_LOOKING_VALUE_12345. Then ran the exact ordinary workflow the GHSA-hmq2-w58f-27jc advisory's own PoC also uses:

repo = Repo.clone_from(evil_parent_url, victim_clone_dir)
repo.submodule_update(init=True, recursive=True)

Observed result (ls .git/modules/):

.git/modules/AKIA_TOTALLY_FAKE_BUT_SECRET_LOOKING_VALUE_12345/   (a full git repo: HEAD, config, objects/, refs/, hooks/)

The literal $GPY_SECRET_MARKER-named directory was never created — only the expanded one exists, proving expansion happened before the value reached the git clone --separate-git-dir=... subprocess argument. The persistent, expanded-name directory under .git/modules/ is itself the primary disclosure channel — it survives on disk for as long as the clone does. A second, independent channel: with the git.cmd/git.repo.base loggers at DEBUG level (a common CI/verbose-logging setting, not requiring any special flag), GitPython's own Popen(...) debug log line prints the fully expanded --separate-git-dir=<value> subprocess argument verbatim — remove_password_if_present() only redacts…

Record
GHSA-fx3j-rwgx-fr94
CVSS 3.1
6.5 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
Weakness
CWE-200
Updated
2026-11-02
OSVUBUNTU-CVE-2026-110855 7.1

GitPython before 3.2.0 contains an information disclosure vulnerability that allows malicious repositories to expand environment variables via separate_git_dir in Repo._clone(), which omits expand_vars=False when calling Git.polish_url(). Attackers can craft a .gitmodules submodule name containing variable syntax so that clone plus submodule_update exposes secrets in .git/modules directory names and DEBUG logs.

Record
UBUNTU-CVE-2026-110855
CVSS 4.0
7.1 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
CVSS 3.1
6.5 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
Updated
2026-11-02
OSVCLSA-2026-1792479054 No score

TuxCare security update for gitpython (7 CVEs)

TuxCare rebuilt gitpython to address 7 CVEs. Fixed in 3.1.31.post15+tuxcare.

Record
CLSA-2026-1792479054
Updated
2026-11-02
OSVMGASA-2026-0580 No score

Updated python-gitpython package fixes security vulnerabilities

Please see the links for additional information.

Record
MGASA-2026-0580
Updated
2026-11-07
OSVopenSUSE-SU-2026:12391-1 No score

python313-GitPython-3.2.1-1.1 on GA media

These are all security issues fixed in the python313-GitPython-3.2.1-1.1 package on the GA media of openSUSE Tumbleweed.

Record
openSUSE-SU-2026:12391-1
Updated
2026-11-03

Affected products

Affected packages

Affected packages
PackageAffectedFixed
gitpython
PyPI
through 3.1.62
3.2.0
gitpython
TuxCare:PyPI
From an advisory covering 4 CVEs
3.1.31 up to 3.1.31.post15+tuxcare, plus listed versions
3.1.31.post1+tuxcare3.1.31.post10+tuxcare3.1.31.post11+tuxcare3.1.31.post12+tuxcare3.1.31.post13+tuxcare
Show 9 moreShow less
3.1.31.post14+tuxcare3.1.31.post2+tuxcare3.1.31.post3+tuxcare3.1.31.post4+tuxcare3.1.31.post5+tuxcare3.1.31.post6+tuxcare3.1.31.post7+tuxcare3.1.31.post8+tuxcare3.1.31.post9+tuxcare
3.1.31.post15+tuxcare
python-git
Debian:12
before 3.1.30-1+deb12u3, plus listed versions
3.1.30-13.1.30-1+deb12u2
3.1.30-1+deb12u3
python-git
Debian:13
before 3.1.44-1+deb13u1, plus listed versions
3.1.44-1
3.1.44-1+deb13u1
python-git
Debian:14
before 3.2.1-1, plus listed versions
3.1.44-13.1.45-13.1.46-13.1.50-13.1.61-13.1.62-13.1.62-23.1.62-3
3.2.1-1
gitpython
PyPI
before 3.2.0, plus listed versions
0.1.70.2.0-beta10.3.0-beta10.3.0-beta20.3.1-beta2
Show 45 moreShow less
0.3.20.3.2.10.3.2.RC10.3.30.3.40.3.50.3.60.3.71.0.01.0.11.0.22.0.02.0.12.0.22.0.32.0.42.0.52.0.62.0.72.0.82.0.92.0.9.dev02.0.9.dev12.1.02.1.12.1.102.1.112.1.122.1.132.1.142.1.152.1.22.1.32.1.42.1.52.1.62.1.72.1.82.1.93.0.03.0.13.0.23.0.33.0.43.0.5
3.2.0
python-gitpython
Mageia:10
From an advisory covering 6 CVEs
before 3.2.1-1.mga10
3.2.1-1.mga10
python-git
Ubuntu:Pro:14.04:LTS
All versions, plus listed versions
0.3.2~RC1-20.3.2~RC1-30.3.2~RC1-3ubuntu0.1~esm10.3.2~RC1-3ubuntu0.1~esm20.3.2~RC1-3ubuntu0.1~esm3
None known
python-git
Ubuntu:Pro:16.04:LTS
All versions, plus listed versions
1.0.1+git137-gc8b8379-11.0.1+git137-gc8b8379-21.0.1+git137-gc8b8379-2.11.0.1+git137-gc8b8379-2.1ubuntu0.1~esm11.0.1+git137-gc8b8379-2.1ubuntu0.1~esm21.0.1+git137-gc8b8379-2.1ubuntu0.1~esm4
None known
python-git
Ubuntu:Pro:18.04:LTS
All versions, plus listed versions
2.1.5-12.1.6-12.1.7-12.1.8-12.1.8-1ubuntu0.1~esm12.1.8-1ubuntu0.1~esm22.1.8-1ubuntu0.1~esm4
None known
Show 6 moreShow less
Affected packages
PackageAffectedFixed
python-git
Ubuntu:Pro:20.04:LTS
All versions, plus listed versions
2.1.11-13.0.4-13.0.5-13.0.7-13.0.7-1ubuntu0.1~esm13.0.7-1ubuntu0.1~esm23.0.7-1ubuntu0.1~esm4
None known
python-git
Ubuntu:Pro:22.04:LTS
All versions, plus listed versions
3.1.14-13.1.23-13.1.24-13.1.24-1ubuntu0.1~esm13.1.24-1ubuntu0.1~esm23.1.24-1ubuntu0.1~esm3
None known
python-git
Ubuntu:Pro:24.04:LTS
All versions, plus listed versions
3.1.30-13.1.37-13.1.37-33.1.37-3ubuntu0.1~esm2
None known
python-git
Ubuntu:26.10
All versions, plus listed versions
3.1.46-13.1.50-13.1.61-1
None known
python-git
Ubuntu:Pro:26.04:LTS
All versions, plus listed versions
3.1.44-13.1.45-13.1.46-13.1.46-1ubuntu0.1~esm1
None known
python-GitPython
openSUSE:Tumbleweed
From an advisory covering 6 CVEs
before 3.2.1-1.1
3.2.1-1.1

History

History
RecordedChangedSources
affected, aliases, referencesOSV
affected
affected, aliases, facts, referencesOSV
affected, aliases, references
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-110855 is a high vulnerability (CVSS 7.1) in Gitpython-developers Gitpython, published October 14, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.29%, the 21st percentile. Fixed in gitpython 3.2.0.

References

Show 17 moreShow less
This page doesn't list everything

Left out here: 65 versions and the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open