CVE-2026-44244: GitPython: git config injection enables hook RCE

GHSA-v87r-6q3f-2j67 HIGH CISA: ATTEND
Published May 6, 2026
CISO Take

GitPython's config writer silently passes newline characters into `.git/config`, allowing any caller who controls `author_name` or `author_email` in a `set_value()` call to inject a `[core] hooksPath` directive that redirects Git hook execution to an attacker-controlled path — every subsequent commit, merge, or checkout on that repository then runs the attacker's scripts. With GitPython embedded as a transitive dependency in DVC, MLflow, and Kedro, the blast radius spans the majority of Python-based MLOps stacks; MLRun's `project.push()` is a confirmed vulnerable call site where these author fields cross a trust boundary with no sanitization. The EPSS model places this in the top 94th percentile for exploitation likelihood, a working PoC requires no specialized skill to reproduce, and the config poisoning persists on disk across restarts — affecting every user who subsequently touches the repository. Patch GitPython to 3.1.49 immediately, audit all `config_writer().set_value()` call sites that accept external input, and monitor `.git/config` files for unexpected `hooksPath` entries.

Sources: NVD EPSS GitHub Advisory ATLAS OpenSSF

What is the risk?

High risk in any shared or multi-user MLOps environment. The CVSS vector (AV:L/AC:L/PR:L/UI:N) means low-privilege local access is sufficient — exactly the access model of shared MLRun servers, Jupyter environments, and CI/CD systems. The persistence mechanism (modifying `.git/config`) survives process restarts and affects all subsequent users interacting with the repository, not just the attacker's session. The OpenSSF Scorecard of 5.3/10 indicates limited upstream security hygiene, and zero historical CVEs in this package suggests the attack surface has been underaudited. In single-user deployments, impact is contained to self-compromise; in multi-user hosted environments, this is a lateral movement primitive.

How does the attack unfold?

Initial Access
Attacker supplies a crafted `author_name` containing an embedded newline payload (`foo\n[core]\nhooksPath=/attacker/path`) to MLRun's `project.push()` API — no special privileges beyond user-level API access required.
AML.T0049
Config Injection
GitPython's `set_value()` writes the unsanitized value to `.git/config`; Git's config parser treats the indented `[core]` stanza as a real section header, activating the injected `core.hooksPath` directive.
AML.T0010.001
Persistence
The poisoned `.git/config` persists on disk, silently redirecting hook execution for all subsequent Git operations by any user or automated process interacting with that repository.
Code Execution
Any commit, merge, or checkout triggers Git to invoke the attacker's hook scripts, achieving arbitrary code execution within the MLOps pipeline with the privileges of the initiating user or CI/CD service account.
AML.T0050

What systems are affected?

Package Ecosystem Vulnerable Range Patched
DVC pip <= 3.1.48 3.1.49
15.7K OpenSSF 5.5 89 dependents Pushed 4d ago 50% patched ~0d to patch Full package profile →
DVC pip No patch
15.7K OpenSSF 5.5 89 dependents Pushed 4d ago 50% patched ~0d to patch Full package profile →
MLflow pip No patch
26.6K OpenSSF 5.6 655 dependents Pushed 4d ago 31% patched ~51d to patch Full package profile →

How severe is it?

CVSS 3.1
7.8 / 10
EPSS
0.2%
chance of exploitation in 30 days
Higher than 9% of all CVEs
Exploitation Status
Exploit Available
Exploitation: MEDIUM
Sophistication
Trivial
Exploitation Confidence
medium
CISA SSVC: Public PoC
Composite signal derived from CISA KEV, VulnCheck KEV, CISA SSVC, EPSS, Metasploit, Exploit-DB, trickest/cve, Nuclei templates, and inthewild.io exploitation reports.

What is the attack surface?

AV AC PR UI S C I A
AV Local
AC Low
PR Low
UI None
S Unchanged
C High
I High
A High

What should I do?

6 steps
  1. Patch GitPython to version 3.1.49 or later — this is the primary fix.

  2. Grep your codebase for config_writer() and set_value() call sites where the value argument derives from external input; apply input validation rejecting CR, LF, and NUL characters.

  3. In MLRun specifically, sanitize author_name and author_email before passing to project.push().

  4. Deploy file integrity monitoring on .git/config in shared repositories — alert on any hooksPath key appearing outside your baseline.

  5. In environments where immediate patching is blocked, apply a compensating control by setting git config --system core.hooksPath /dev/null to disable hooks at the system level.

  6. Audit DVC, MLflow, and Kedro integrations for externally-influenced strings reaching set_value() — these are high-confidence secondary attack surfaces.

What does CISA's SSVC say?

Decision Attend
Exploitation poc
Automatable No
Technical Impact total

Source: CISA Vulnrichment (SSVC v2.0). Decision based on the CISA Coordinator decision tree.

How is it classified?

Which compliance frameworks are affected?

This CVE is relevant to:

EU AI Act
Article 15 - Accuracy, robustness and cybersecurity
ISO 42001
A.6.2.3 - AI system supply chain management
NIST AI RMF
GOVERN 6.1 - Policies and procedures are in place for AI risk management across the supply chain
OWASP LLM Top 10
LLM05 - Supply Chain Vulnerabilities

Frequently Asked Questions

What is CVE-2026-44244?

GitPython's config writer silently passes newline characters into `.git/config`, allowing any caller who controls `author_name` or `author_email` in a `set_value()` call to inject a `[core] hooksPath` directive that redirects Git hook execution to an attacker-controlled path — every subsequent commit, merge, or checkout on that repository then runs the attacker's scripts. With GitPython embedded as a transitive dependency in DVC, MLflow, and Kedro, the blast radius spans the majority of Python-based MLOps stacks; MLRun's `project.push()` is a confirmed vulnerable call site where these author fields cross a trust boundary with no sanitization. The EPSS model places this in the top 94th percentile for exploitation likelihood, a working PoC requires no specialized skill to reproduce, and the config poisoning persists on disk across restarts — affecting every user who subsequently touches the repository. Patch GitPython to 3.1.49 immediately, audit all `config_writer().set_value()` call sites that accept external input, and monitor `.git/config` files for unexpected `hooksPath` entries.

Is CVE-2026-44244 actively exploited?

No confirmed active exploitation of CVE-2026-44244 has been reported, but organizations should still patch proactively.

How to fix CVE-2026-44244?

1. Patch GitPython to version 3.1.49 or later — this is the primary fix. 2. Grep your codebase for `config_writer()` and `set_value()` call sites where the value argument derives from external input; apply input validation rejecting CR, LF, and NUL characters. 3. In MLRun specifically, sanitize `author_name` and `author_email` before passing to `project.push()`. 4. Deploy file integrity monitoring on `.git/config` in shared repositories — alert on any `hooksPath` key appearing outside your baseline. 5. In environments where immediate patching is blocked, apply a compensating control by setting `git config --system core.hooksPath /dev/null` to disable hooks at the system level. 6. Audit DVC, MLflow, and Kedro integrations for externally-influenced strings reaching `set_value()` — these are high-confidence secondary attack surfaces.

What systems are affected by CVE-2026-44244?

This vulnerability affects the following AI/ML architecture patterns: MLOps pipelines, CI/CD pipelines with Git-backed model versioning, Shared ML development environments, Training pipelines, Model versioning systems.

What is the CVSS score for CVE-2026-44244?

CVE-2026-44244 has a CVSS v3.1 base score of 7.8 (HIGH). The EPSS exploitation probability is 0.19%.

What is the AI security impact?

Affected AI Architectures

MLOps pipelinesCI/CD pipelines with Git-backed model versioningShared ML development environmentsTraining pipelinesModel versioning systems

MITRE ATLAS Techniques

AML.T0010.001 AI Software
AML.T0049 Exploit Public-Facing Application
AML.T0050 Command and Scripting Interpreter

Compliance Controls Affected

EU AI Act: Article 15
ISO 42001: A.6.2.3
NIST AI RMF: GOVERN 6.1
OWASP LLM Top 10: LLM05

What are the technical details?

Original Advisory

`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. The vulnerability is not merely malformed config output: GitPython's own writer converts embedded newlines into indented continuation lines, but Git still accepts an indented `[core]` stanza as a section header, so the injected `core.hooksPath` becomes effective configuration. This was found while auditing MLRun's `project.push()` method, which passes `author_name` and `author_email` directly to `config_writer().set_value()` with no sanitization. Both parameters cross a trust boundary — they are caller-supplied API inputs that end up in `.git/config`. PoC (standalone, no MLRun required): ```python import git, subprocess, os repo = git.Repo("/tmp/testrepo") with repo.config_writer() as cw: cw.set_value("user", "name", "foo\n[core]\nhooksPath=/tmp/hooks") r = subprocess.run(["git", "config", "core.hooksPath"], cwd="/tmp/testrepo", capture_output=True, text=True) assert r.returncode == 0 print(r.stdout.strip()) # /tmp/hooks os.makedirs("/tmp/hooks", exist_ok=True) open("/tmp/hooks/pre-commit", "w").write("#!/bin/sh\nid > /tmp/pwned\n") os.chmod("/tmp/hooks/pre-commit", 0o755) repo.index.add(["README"]) repo.git.commit(m="test") print(open("/tmp/pwned").read()) # uid=... ``` Tested on GitPython 3.1.46, git 2.39+. Impact: This is persistent repo config poisoning. Any user who can supply `author_name` or `author_email` to an application calling `config_writer().set_value()` can redirect Git hook execution to an arbitrary path. In a multi-user or hosted environment (e.g. a shared MLRun server where multiple users push to the same repositories), one user can poison the `.git/config` of a shared repo and have their hooks run in the context of every subsequent Git operation by any user. On single-user deployments, the impact depends on whether the application later invokes Git hooks automatically. Remediation: `set_value()` should raise on CR, LF, or NUL in values rather than silently pass them through: ```python import re if isinstance(value, (str, bytes)) and re.search(r"[\r\n\x00]", str(value)): raise ValueError("Git config values must not contain CR, LF, or NUL") ``` Rejecting is safer than stripping — a stripped newline might indicate the caller is passing unsanitized input at a higher level, and silent normalization masks that. Affected wherever `config_writer().set_value(section, key, user_input)` is called with external input.** GitPython is a dependency of DVC, MLflow, Kedro, and others — worth auditing their `set_value()` call sites for externally influenced inputs.

Exploitation Scenario

An attacker with user-level access to a shared MLRun server submits a model training job with `author_name` set to `researcher\n[core]\nhooksPath=/tmp/attacker_hooks`. MLRun passes this directly to `config_writer().set_value('user', 'name', ...)` with no sanitization. GitPython writes the value to `.git/config`, and Git's parser interprets the indented `[core]` stanza as a real section header, making `core.hooksPath=/tmp/attacker_hooks` immediately effective. The attacker pre-places a `pre-commit` shell script at that path. From this point forward, every automated CI/CD pipeline commit pushing model checkpoints — and every developer commit on the shared repo — executes the attacker's hook with the committing user's privileges, enabling credential exfiltration, model artifact tampering, or lateral movement into downstream infrastructure.

Weaknesses (CWE)

CWE-94 — Improper Control of Generation of Code ('Code Injection'): The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.

  • [Architecture and Design] Refactor your program so that you do not have to dynamically generate code.
  • [Architecture and Design] Run your code in a "jail" or similar sandbox environment that enforces strict boundaries between the process and the operating system. This may effectively restrict which code can be executed by your product. Examples include the Unix chroot jail and AppArmor. In general, managed code may provide some protection. This may not be a feasible solution, and it only limits the impact to the operating system; the rest of your application may still be subject to compromise. Be careful to avoid CWE-243 and other weaknesses related to jails.

Source: MITRE CWE corpus.

CVSS Vector

CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Timeline

Published
May 6, 2026
Last Modified
May 6, 2026
First Seen
May 7, 2026

Related Vulnerabilities