GHSA-whh4-5q6c-9v3x: GitPython --no-index Bypasses Diff Unsafe-option Protections Vulnerability
MODERATEGHSA-whh4-5q6c-9v3x is a MODERATE (CVSS 6.5) --no-index bypasses diff unsafe-option protections vulnerability (CWE-88: Improper Neutralization of Argument Delimiters in a Command ('Argument Injection')) affecting GitPython libraries in the PyPI ecosystem. The issue involves --no-index bypasses diff unsafe-option protections and enables a blind local-file content oracle. Remediation is available by upgrading affected packages to version 3.1.60.
GHSA-whh4-5q6c-9v3x at a Glance
Security Impact
CVSS: 6.5
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N).
How to Fix GHSA-whh4-5q6c-9v3x
To remediate this vulnerability, upgrade all affected GitPython dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
pip install gitpython>=3.1.60
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
pip show gitpython
How to Check if You Are Affected
To determine whether your Python environment is affected by GHSA-whh4-5q6c-9v3x, inspect your installed packages using pip:
pip show gitpython
Analyze the terminal output to locate any version of GitPython in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 3.1.60), your application is affected.
Note: The pip show gitpython command checks currently installed packages in your active Python environment.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-88: Improper Neutralization of Argument Delimiters in a Command ('Argument Injection'), where the product constructs a string for a command to be executed by a separate component in another control sphere, but it does not properly delimit the intended arguments, options, or switches within that command string. In GitPython, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
GHSA-whh4-5q6c-9v3x Affected GitPython Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
gitpython
|
PyPI |
≥ 3.1.59
< 3.1.60
|
3.1.60
|
References
Frequently Asked Questions
What is GHSA-whh4-5q6c-9v3x?
Which GitPython versions are affected?
What version fixes GHSA-whh4-5q6c-9v3x?
Is gitpython affected?
What is the CVSS score of GHSA-whh4-5q6c-9v3x?
What CWE is associated with GHSA-whh4-5q6c-9v3x?
How can I check PyPI dependencies for GHSA-whh4-5q6c-9v3x?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-whh4-5q6c-9v3x",
"modified" : "2026-09-30T23:28:40Z",
"published" : "2026-09-30T23:28:40Z",
"aliases" : [ ],
"summary" : "GitPython: --no-index bypasses diff unsafe-option protections and enables a blind local-file content oracle",
"details" : "### Summary\n\nGitPython 3.1.59 blocks a previously available local-file read path through unsafe git diff options such as -O/--orderfile.\n\nHowever, the high-level diff API still permits --no-index with the default allow_unsafe_options=False.\n\n--no-index changes the semantics of the paths arguments: instead of repository-relative pathspecs, Git interprets them as arbitrary filesystem paths.\n\nWhen combined with the still-allowed -I/--ignore-matching-lines option, this creates a content-dependent Boolean oracle over a caller-selected local file.\n\nThis was reproduced against the published GitPython 3.1.59 wheel.\n\nThe original unsafe-option path is blocked in 3.1.59, while this alternate path remains reachable without setting allow_unsafe_options=True.\n\n### Details\n\nConfirmed API surface:\n\nrepo.index.diff(\n None,\n no_index=True,\n I=pattern,\n paths=[baseline_path, target_path],\n create_patch=True,\n)\n\nThe relevant behavior is:\n\n1. --no-index makes the two values supplied via paths filesystem operands rather than repository pathspecs.\n2. -I/--ignore-matching-lines makes Git's result depend on whether the supplied regular expression matches the relevant file content.\n3. GitPython exposes the resulting bit through distinguishable behavior:\n - matching condition: normal return with an empty DiffIndex\n - non-matching condition: GitCommandError with exit status 1\n\nAn application that forwards attacker-influenced diff options and paths and exposes the success/error distinction can therefore be queried repeatedly to recover a guessable local single-line secret.\n\nThe issue was confirmed with the default allow_unsafe_options=False.\n\nThe behavior does not require the caller to explicitly opt into GitPython's unsafe-option mode.\n\nVerified intended security boundary:\n\n- GitPython 3.1.58 accepts the earlier -O/--orderfile local-file input path.\n- GitPython 3.1.59 rejects that same path with UnsafeOptionError.\n- GitPython 3.1.59 still permits the --no-index alternate path described above.\n\nThis appears to be an alternate route to the same local-file confidentiality property that the 3.1.59 diff option hardening is intended to protect.\n\n### PoC\n\nA minimal reproducer, controlled extraction demonstrator, proof matrix, and proposed remediation are included in the attached package.\n\n[gitpython-3159-maintainer-evidence.zip](https://github.com/user-attachments/files/31123571/gitpython-3159-maintainer-evidence.zip)\n\n\nThe minimal reproducer creates only temporary researcher-controlled files and demonstrates the following predicate:\n\ncorrect prefix -> normal GitPython return\nincorrect prefix -> GitCommandError(status=1)\n\nIn the controlled extraction test, I generated three independent random single-line values and recovered all three exactly through repeated calls to the GitPython high-level API.\n\nResult: 3/3 recovered.\n\nThe extraction harness also installs a Python audit hook that rejects direct Python open() access to the target file during the oracle phase. The content-dependent read is therefore performed by the child git process invoked through GitPython rather than by the reproduction script directly.\n\nControls were also tested:\n\n- normal repository-scoped diff: no secret disclosure\n- same outside paths without --no-index: no arbitrary-filesystem interpretation\n- deliberately incorrect predicate: status 1 as expected\n\nSuggested remediation is to classify --no-index as unsafe for the high-level diff API unless the caller explicitly sets allow_unsafe_options=True.\n\n### Impact\n\nPotential impact is disclosure of local files readable by the process running GitPython.\n\nExploitation requires an embedding application to allow an attacker to influence:\n\n1. the relevant diff options,\n2. both path operands, and\n3. repeated requests while exposing a distinguishable success/error result.\n\nThe demonstrated attack is a blind content oracle rather than a one-request in-band file read. It is particularly applicable to short or structured single-line secrets where the target path and approximate value format are known or guessable.\n\nConfirmed affected release: GitPython 3.1.59.",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "PyPI",
"name" : "gitpython"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "3.1.59"
}, {
"fixed" : "3.1.60"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-whh4-5q6c-9v3x"
}, {
"type" : "WEB",
"url" : "https://github.com/gitpython-developers/GitPython/pull/2217"
}, {
"type" : "WEB",
"url" : "https://github.com/gitpython-developers/GitPython/commit/09f2cf383a992d1af697364569e9f384748c1bd8"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/gitpython-developers/GitPython"
}, {
"type" : "WEB",
"url" : "https://github.com/gitpython-developers/GitPython/releases/tag/3.1.60"
}, {
"type" : "WEB",
"url" : "https://github.com/pypa/advisory-database/tree/main/vulns/gitpython/PYSEC-2026-3983.yaml"
}, {
"type" : "WEB",
"url" : "https://www.vulncheck.com/advisories/gitpython-3.1.59-local-file-content-oracle-via-no-index"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-200", "CWE-88" ],
"severity" : "MODERATE",
"github_reviewed" : true,
"github_reviewed_at" : "2026-09-30T23:28:40Z",
"nvd_published_at" : null
}
}