GHSA-M64X-33Q8-M5H7

GHSA-M64X-33Q8-M5H7 is a high-severity inefficient regular expression (ReDoS) vulnerability in GitPython (pip), affecting versions <= 3.1.62. It is fixed in 3.2.0.

Does this CVE actually affect you?

Kodem shows which CVEs are reachable and running in your applications, so you fix what's exploitable, not just what's listed.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Runtime intelligence, not another scanner.

Summary

GitPython parseactorand_date() is vulnerable to quadratic backtracking on malformed identity lines

This is a residual of GHSA-g5vv-9gxw-82hx / CVE-2026-87819. The 3.1.60 fix made Actor._from_string regex-free, but parse_actor_and_date still runs _re_actor_epoch on the same author/committer/tagger line one step earlier. That pattern backtracks quadratically when the trailing epoch or timezone is missing or malformed, so the same class of slow parse is still reachable in 3.1.62.

Details

git/objects/util.py:322:

_re_actor_epoch = re.compile(r"^.+? (.*) (\d+) ([+-]\d+).*$")

.+? and (.*) can both absorb the same run of spaces, and the required (\d+) ([+-]\d+) tail is only checked after them. On a long line with no valid tail, the search retries every split point.

It is called from parse_actor_and_date (git/objects/util.py:335), which runs on the author and committer lines in Commit._deserialize (git/objects/commit.py:917, :931) and on the tagger line in git/objects/tag.py:129.

The published payload (letters plus an unterminated <) is fast on 3.1.62. Replacing the letters with spaces is not:

author line (after author ) 2 KB 8 KB 32 KB
'a'*n + ' <' (advisory payload) 0.0 ms 0.1 ms 0.4 ms
' '*n 28 ms 453 ms 7,700 ms
valid line, long name (control) 0.0 ms 0.0 ms 0.0 ms

Cost grows about 16x for each 4x increase in length.

PoC

import time
from git.objects.util import parse_actor_and_date

line = "author " + " " * 32000
t = time.perf_counter()
parse_actor_and_date(line)
print(f"{time.perf_counter() - t:.1f} s")   # ~7 s on 3.1.62

End to end, reading Commit.author on a commit object whose author line is 32 KB of spaces followed by any malformed tail (no epoch, no timezone, non-numeric epoch, or bad timezone) takes about 7.2 s per access. The same line with a valid 1191999972 -0700 tail takes 1.3 ms.

Note for reproducing: git hash-object -t commit -w refuses such an object (missingEmail), so the test object was written with --literally. A remote can still serve one, because fetch.fsckObjects and transfer.fsckObjects default to false. This is the same delivery model as CVE-2026-87819 ("craft a commit object with a malformed author field").

Brian Willows

Impact

CPU exhaustion (CWE-1333) in any application that uses GitPython to read commits or tags from an untrusted repository: CI tooling, repository scanners, code-hosting integrations. Each access to Commit.author, Commit.committer or TagObject.tagger on a crafted object costs seconds, and a repository can contain many such objects.

A regular expression with worst-case exponential or polynomial matching time is applied to untrusted input, causing excessive CPU use. Typical impact: denial of service when input is crafted to trigger backtracking.

Affected versions

GitPython (<= 3.1.62)

Security releases

GitPython → 3.2.0 (pip)

Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.

Already deployed Kodem?

See it in your environmentNew to Kodem? Get a demo →

Remediation advice

Match the leading field name with .[^ ]* instead of .+?. Both stop at the first space after the first character, but .[^ ]* cannot overlap the following (.*), so the backtracking disappears:

_re_actor_epoch = re.compile(r"^.[^ ]* (.*) (\d+) ([+-]\d+).*$")
_re_only_actor = re.compile(r"^.[^ ]* (.*)$")

Verification on current main (73a72c9):

  • Differential over 368 actor lines (real-world shapes plus edge cases): 0 differences in match groups for either regex.
  • ' '*n at 64 KB: 32,170 ms before, 0.98 ms after. Valid lines are unchanged (0.01 ms).
  • The existing test suite gives the same pass/fail set with and without the change
  • The new regression test, test_parse_actor_and_date_malformed_line_is_linear, fails on the old pattern (8.4 s) and passes with the fix (0.5 s).

The full patch (fix plus regression test) is attached below.

diff --git a/git/objects/util.py b/git/objects/util.py
index a68d701f..d8c0594d 100644
--- a/git/objects/util.py
+++ b/git/objects/util.py
@@ -319,8 +319,11 @@ def parse_date(string_date: Union[str, datetime]) -> Tuple[int, int]:
 
 
 # Precompiled regexes
-_re_actor_epoch = re.compile(r"^.+? (.*) (\d+) ([+-]\d+).*$")
-_re_only_actor = re.compile(r"^.+? (.*)$")
+# The leading field name ("author", "committer", "tagger") is matched with ``.[^ ]*`` rather than
+# ``.+?``: both stop at the first space after the first character, but ``.[^ ]*`` cannot overlap the
+# following ``(.*)``, so a line with no valid trailing epoch/offset no longer backtracks quadratically.
+_re_actor_epoch = re.compile(r"^.[^ ]* (.*) (\d+) ([+-]\d+).*$")
+_re_only_actor = re.compile(r"^.[^ ]* (.*)$")
 
 
 def parse_actor_and_date(line: str) -> Tuple[Actor, int, int]:
diff --git a/test/test_util.py b/test/test_util.py
index cf4299d5..e1631420 100644
--- a/test/test_util.py
+++ b/test/test_util.py
@@ -22,6 +22,7 @@ from git.cmd import dashify
 from git.objects.util import (
     altz_to_utctz_str,
     from_timestamp,
+    parse_actor_and_date,
     parse_date,
     tzoffset,
     utctz_to_altz,
@@ -571,6 +572,30 @@ class TestUtils(TestBase):
             Actor("name last another", "[email protected]"),
         )
 
+    def test_parse_actor_and_date_malformed_line_is_linear(self):
+        # A long author line whose trailing epoch/offset is missing or malformed used to make
+        # _re_actor_epoch backtrack quadratically: ~7 s per Commit.author access for a 32 KB line.
+        # The parse result must be unchanged; only the time spent reaching it should move.
+        for tail in ("", " notanumber -0700", " 1191999972", " -0700", " 1191999972 xx"):
+            line = "author " + " " * 32000 + tail
+            start = time.perf_counter()
+            actor, epoch, offset = parse_actor_and_date(line)
+            self.assertLess(time.perf_counter() - start, 1.0)
+            self.assertEqual(epoch, 0)
+            self.assertEqual(offset, 0)
+
+        # Well-formed lines, including one with a long name, still parse exactly as before.
+        actor, epoch, offset = parse_actor_and_date(
+            "author Tom Preston-Werner <[email protected]> 1191999972 -0700"
+        )
+        self.assertEqual(actor, Actor("Tom Preston-Werner", "[email protected]"))
+        self.assertEqual(epoch, 1191999972)
+        self.assertEqual(offset, 25200)
+
+        actor, epoch, offset = parse_actor_and_date("author " + "a " * 16000 + "<a@b> 1 -0700")
+        self.assertEqual(actor.email, "a@b")
+        self.assertEqual(epoch, 1)
+
     @ddt.data(
         ("name", ""),
         ("name", "prefix_"),

Found with AI assistance (Claude) and verified by hand.

Frequently Asked Questions

  1. What is GHSA-M64X-33Q8-M5H7? GHSA-M64X-33Q8-M5H7 is a high-severity inefficient regular expression (ReDoS) vulnerability in GitPython (pip), affecting versions <= 3.1.62. It is fixed in 3.2.0. A regular expression with worst-case exponential or polynomial matching time is applied to untrusted input, causing excessive CPU use.
  2. Which versions of GitPython are affected by GHSA-M64X-33Q8-M5H7? GitPython (pip) versions <= 3.1.62 is affected.
  3. Is there a fix for GHSA-M64X-33Q8-M5H7? Yes. GHSA-M64X-33Q8-M5H7 is fixed in 3.2.0. Upgrade to this version or later.
  4. Is GHSA-M64X-33Q8-M5H7 exploitable, and should I be worried? Whether GHSA-M64X-33Q8-M5H7 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
  5. What actually determines whether GHSA-M64X-33Q8-M5H7 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
  6. How do I fix GHSA-M64X-33Q8-M5H7? Upgrade GitPython to 3.2.0 or later.

Other vulnerabilities in GitPython

Stop the waste.
Protect your environment with Kodem.