GHSA-5xxx-qhh7-9287: Infoleak

Published Sep 8, 2026
·
Updated

Summary Repo.blame() / Repo.blameincremental() guard forwarded revision options against unsafegitrevisionoptions, but that denylist only contains the file-WRITE options --output/-o. git blame also honors --contents <file> and -S <file>, which cause the file's lines to be echoed into the blame result — an arbitrary file READ. Neither option is in the denylist, so a caller-influenced revision value of --contents=<path> passes the guard and leaks file contents. This is a distinct sink-option and impact class (READ) from GHSA-956x-8gvw-wg5v (which addressed the blame --output WRITE), directly analogous to GHSA-539m-9xh6-q6rr (archive READ gap accepted separately from the archive write/exec advisory).

Root Cause unsafegitrevisionoptions = ["--output","-o"] (git/repo/base.py:188). The rev string is passed to optioncandidates([rev], kwargs) and placed BEFORE the -- separator (base.py:841). The canonical name of --contents=... is contents, which is not on the denylist, so no UnsafeOptionError is raised. The trailing -- protects only the pathspec, not the option before the revision.

Impact Arbitrary local file read at the privileges of the host process; the file's line contents appear in the blame result returned to the caller. Pure VALUE control (the caller forwards a user-influenced revision string). Default allowunsafeoptions=False.

Proof of Concept python result = repo.blame("--contents=/etc/passwd", "a.txt") result rows carry the victim file's line text

Attack Chain 1. Entry: app calls repo.blame(rev, file) with attacker rev="--contents=/etc/passwd" (or kwarg contents="/etc/passwd", or -S). 2. Check: Git.checkunsafeoptions(optioncandidates([rev,...], kwargs), unsafegitrevisionoptions) @ base.py:841. Guard: denylist = ["--output","-o"] only. Bypass proof: canonical name contents ∉ denylist → no error. 3. Sink: self.git.blame(rev, "--", file, p=True, ...). argv (observed): ['git','blame','-p','--contents=<secret>','HEAD','--','a.txt']. 4. Impact: blame result rows carry the victim file's line text.

Bypass Evidence Independently reproduced (independent test harness, default allowunsafeoptions=False): blame('--contents=<secret>','a.txt') → guard PASSED; result rows = ['GATESECRETLINEA','GATESECRETLINEB']. Control: blame('--output=…') still BLOCKED (guard active on this path). -S kwarg argv also reaches git unguarded.

Affected Versions GitPython <= 3.1.58 (denylist present verbatim on the latest release tag).

Suggested Fix Prefer an allowlist of blame options; at minimum add --contents/-S (and any other path-taking blame options) to unsafegitrevisionoptions, and make the membership rule "the option takes a filesystem path" rather than "the option writes output".

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

Affected Software

1 affected componentFixes available
pip/GitPython<=3.1.58
3.1.59

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.1.59
  2. Configuration

    Update the deny/unsafe option list used by `Git.check_unsafe_options(_option_candidates([rev,...], kwargs), unsafe_git_revision_options)` so that caller-influenced revision/options cannot include blame file path readers. At minimum, add `--contents`/`-S` (and any other blame options that take a filesystem path) to `unsafe_git_revision_options`, and base the rule on whether the option takes a filesystem path (not whether the option writes output).

    GitPython Repo.blame / Repo.blame_incremental (unsafe option guard) unsafe_git_revision_options = Add/extend to include path-taking blame options such as --contents and -S

Event History

Sep 8, 2026
Advisory Published
via GitHub·06:41 PM
Data Sourced
via GitHub·06:41 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Which deployments are exposed?

Applications using GitPython are exposed when they pass caller-influenced revision values to Repo.blame() or Repo.blame_incremental(). The affected process can disclose local files that it is permitted to read.

2

What must an attacker be able to do?

An attacker needs the ability to influence the revision argument supplied to one of the affected blame methods. A value using --contents=<path> can be interpreted as a Git option before the argument separator and cause the referenced file's contents to appear in the blame result.

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