CVE-2026-44244: GitPython: git config injection enables hook RCE
GHSA-v87r-6q3f-2j67 HIGH CISA: ATTENDGitPython'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.
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?
What systems are affected?
How severe is it?
What is the attack surface?
What should I do?
6 steps-
Patch GitPython to version 3.1.49 or later — this is the primary fix.
-
Grep your codebase for
config_writer()andset_value()call sites where the value argument derives from external input; apply input validation rejecting CR, LF, and NUL characters. -
In MLRun specifically, sanitize
author_nameandauthor_emailbefore passing toproject.push(). -
Deploy file integrity monitoring on
.git/configin shared repositories — alert on anyhooksPathkey appearing outside your baseline. -
In environments where immediate patching is blocked, apply a compensating control by setting
git config --system core.hooksPath /dev/nullto disable hooks at the system level. -
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?
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:
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
MITRE ATLAS Techniques
AML.T0010.001 AI Software AML.T0049 Exploit Public-Facing Application AML.T0050 Command and Scripting Interpreter Compliance Controls Affected
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 References
Timeline
Related Vulnerabilities
CVE-2025-59528 10.0 Flowise: Unauthenticated RCE via MCP config injection
Same attack type: Supply Chain CVE-2024-2912 10.0 BentoML: RCE via insecure deserialization (CVSS 10)
Same attack type: Supply Chain CVE-2023-3765 10.0 MLflow: path traversal allows arbitrary file read
Same attack type: Supply Chain CVE-2025-5120 10.0 smolagents: sandbox escape enables unauthenticated RCE
Same attack type: Supply Chain CVE-2026-21858 10.0 n8n: Input Validation flaw enables exploitation
Same attack type: Code Execution