python3-git: fix CVE-2026-44243

This patch applies the upstream 3.1.48 backport for
CVE-2026-44243. The upstream fix merge is referenced in [1],
and the public CVE advisory is referenced in [2]. The individual
backported commits are referenced in [3] and [4].

[1] dbfa264764
[2] https://nvd.nist.gov/vuln/detail/CVE-2026-44243
[3] 25ba54dd3f
[4] 4af8463cca

(From OE-Core rev: 0853d0c72e96a3c4e3a5329589a9aa151e2f2c46)

Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com>
Signed-off-by: Yoann Congal <yoann.congal@smile.fr>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Darsh Kelaiya
2026-08-19 10:10:24 -07:00
committed by Richard Purdie
parent 1e39c2a5e3
commit 96afd71237
3 changed files with 224 additions and 0 deletions

View File

@@ -0,0 +1,136 @@
From fcd8d016816696780c0dc96dacbe48fc10df80f6 Mon Sep 17 00:00:00 2001
From: "GPT 5.5" <codex@openai.com>
Date: Tue, 28 Apr 2026 09:17:31 +0800
Subject: [PATCH] prevent out-of-repo access when manipulating references.
This previously made it possible to create, modify and delete files outside outside
of the repository, which is a problem if inputs aren't trusted.
CVE: CVE-2026-44243
Upstream-Status: Backport [https://github.com/gitpython-developers/GitPython/commit/25ba54dd3fb374b8fade7de4be1ac2ac84722190]
Backport Changes:
- Omit regression tests because the Scarthgap PyPI source
archive does not include the upstream test suite.
Co-authored-by: Sebastian Thiel <sebastian.thiel@icloud.com>
(cherry picked from commit 25ba54dd3fb374b8fade7de4be1ac2ac84722190)
Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com>
---
git/refs/log.py | 2 +-
git/refs/remote.py | 5 +++--
git/refs/symbolic.py | 37 +++++++++++++++++++++++++++++++------
3 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/git/refs/log.py b/git/refs/log.py
index e45798d8..29293f4a 100644
--- a/git/refs/log.py
+++ b/git/refs/log.py
@@ -204,7 +204,7 @@ class RefLog(List[RefLogEntry], Serializable):
file though.
:param ref: SymbolicReference instance
"""
- return osp.join(ref.repo.git_dir, "logs", to_native_path(ref.path))
+ return to_native_path(ref._get_validated_reflog_path(ref.repo, ref.path))
@classmethod
def iter_entries(cls, stream: Union[str, "BytesIO", mmap]) -> Iterator[RefLogEntry]:
diff --git a/git/refs/remote.py b/git/refs/remote.py
index 59d02a75..e50c54eb 100644
--- a/git/refs/remote.py
+++ b/git/refs/remote.py
@@ -64,12 +64,13 @@ class RemoteReference(Head):
# are generally ignored in the refs/ folder. We don't though
# and delete remainders manually.
for ref in refs:
+ cls._check_ref_name_valid(ref.path)
try:
- os.remove(os.path.join(repo.common_dir, ref.path))
+ os.remove(cls._get_validated_path(repo.common_dir, ref.path))
except OSError:
pass
try:
- os.remove(os.path.join(repo.git_dir, ref.path))
+ os.remove(cls._get_validated_path(repo.git_dir, ref.path))
except OSError:
pass
# END for each ref
diff --git a/git/refs/symbolic.py b/git/refs/symbolic.py
index 31f959ac..d5c18290 100644
--- a/git/refs/symbolic.py
+++ b/git/refs/symbolic.py
@@ -109,6 +109,32 @@ class SymbolicReference:
def abspath(self) -> PathLike:
return join_path_native(_git_dir(self.repo, self.path), self.path)
+ @staticmethod
+ def _get_validated_path(base: PathLike, path: PathLike) -> str:
+ path = os.fspath(path)
+ base_path = os.path.realpath(os.fspath(base))
+ abs_path = os.path.realpath(os.path.join(base_path, path))
+ try:
+ common_path = os.path.commonpath([base_path, abs_path])
+ except ValueError as e:
+ raise ValueError("Reference path %r escapes the repository" % path) from e
+ if os.path.normcase(common_path) != os.path.normcase(base_path):
+ raise ValueError("Reference path %r escapes the repository" % path)
+ return abs_path
+
+ @classmethod
+ def _get_validated_ref_path(cls, repo: "Repo", path: PathLike) -> str:
+ """Return the absolute filesystem path for a ref after validating it."""
+ cls._check_ref_name_valid(path)
+ ref_path = os.fspath(path)
+ return cls._get_validated_path(_git_dir(repo, ref_path), ref_path)
+
+ @classmethod
+ def _get_validated_reflog_path(cls, repo: "Repo", path: PathLike) -> str:
+ """Return the absolute filesystem path for a reflog after validating it."""
+ cls._check_ref_name_valid(path)
+ return cls._get_validated_path(os.path.join(repo.git_dir, "logs"), path)
+
@classmethod
def _get_packed_refs_path(cls, repo: "Repo") -> str:
return os.path.join(repo.common_dir, "packed-refs")
@@ -442,7 +468,7 @@ class SymbolicReference:
# END handle non-existing
# END retrieve old hexsha
- fpath = self.abspath
+ fpath = self._get_validated_ref_path(self.repo, self.path)
assure_directory_exists(fpath, is_file=True)
lfd = LockedFD(fpath)
@@ -571,7 +597,7 @@ class SymbolicReference:
Alternatively the symbolic reference to be deleted.
"""
full_ref_path = cls.to_full_path(path)
- abs_path = os.path.join(repo.common_dir, full_ref_path)
+ abs_path = cls._get_validated_ref_path(repo, full_ref_path)
if os.path.exists(abs_path):
os.remove(abs_path)
else:
@@ -635,9 +661,8 @@ class SymbolicReference:
corresponding object and a detached symbolic reference will be created
instead.
"""
- git_dir = _git_dir(repo, path)
full_ref_path = cls.to_full_path(path)
- abs_ref_path = os.path.join(git_dir, full_ref_path)
+ abs_ref_path = cls._get_validated_ref_path(repo, full_ref_path)
# Figure out target data.
target = reference
@@ -724,8 +749,8 @@ class SymbolicReference:
if self.path == new_path:
return self
- new_abs_path = os.path.join(_git_dir(self.repo, new_path), new_path)
- cur_abs_path = os.path.join(_git_dir(self.repo, self.path), self.path)
+ new_abs_path = self._get_validated_ref_path(self.repo, new_path)
+ cur_abs_path = self._get_validated_ref_path(self.repo, self.path)
if os.path.isfile(new_abs_path):
if not force:
# If they point to the same file, it's not an error.
--
2.35.6

View File

@@ -0,0 +1,86 @@
From 2d1f681978b51ffff0db57cf89b0bcd6bffc7418 Mon Sep 17 00:00:00 2001
From: "GPT 5.5" <codex@openai.com>
Date: Tue, 28 Apr 2026 09:30:41 +0800
Subject: [PATCH] address review feedback and CI failures
Consolidate follow-up fixes from review and CI:
- fix lint and mypy issues in reference log path handling
- validate remote reference paths before invoking git branch deletion
- add symlink escape coverage where realpath resolves symlinks
- ensure temporary test repositories release git resources during cleanup
CVE: CVE-2026-44243
Upstream-Status: Backport [https://github.com/gitpython-developers/GitPython/commit/4af8463cca31c2369312fcaa5309dfc30756c7b6]
Backport Changes:
- Keep the 3.1.42 docstring layout and path coercion while
applying upstream validation documentation and return type.
- Omit regression test updates because the Scarthgap PyPI
source archive does not include the upstream test suite.
Co-authored-by: Sebastian Thiel <sebastian.thiel@icloud.com>
(cherry picked from commit 4af8463cca31c2369312fcaa5309dfc30756c7b6)
Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com>
---
git/refs/log.py | 3 ++-
git/refs/remote.py | 4 +++-
git/util.py | 2 +-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/git/refs/log.py b/git/refs/log.py
index 29293f4a..eef525e7 100644
--- a/git/refs/log.py
+++ b/git/refs/log.py
@@ -21,7 +21,6 @@ from git.util import (
file_contents_ro_filepath,
)
-import os.path as osp
# typing ------------------------------------------------------------------
@@ -203,6 +202,8 @@ class RefLog(List[RefLogEntry], Serializable):
instance would be found. The path is not guaranteed to point to a valid
file though.
:param ref: SymbolicReference instance
+ :raise ValueError:
+ If `ref.path` is invalid or escapes the repository's reflog directory.
"""
return to_native_path(ref._get_validated_reflog_path(ref.repo, ref.path))
diff --git a/git/refs/remote.py b/git/refs/remote.py
index e50c54eb..70eada81 100644
--- a/git/refs/remote.py
+++ b/git/refs/remote.py
@@ -59,12 +59,14 @@ class RemoteReference(Head):
kwargs are given for comparability with the base class method as we
should not narrow the signature.
"""
+ for ref in refs:
+ cls._check_ref_name_valid(ref.path)
+
repo.git.branch("-d", "-r", *refs)
# The official deletion method will ignore remote symbolic refs - these
# are generally ignored in the refs/ folder. We don't though
# and delete remainders manually.
for ref in refs:
- cls._check_ref_name_valid(ref.path)
try:
os.remove(cls._get_validated_path(repo.common_dir, ref.path))
except OSError:
diff --git a/git/util.py b/git/util.py
index 03d62ffc..5a136d18 100644
--- a/git/util.py
+++ b/git/util.py
@@ -272,7 +272,7 @@ def join_path(a: PathLike, *p: PathLike) -> PathLike:
if os.name == "nt":
- def to_native_path_windows(path: PathLike) -> PathLike:
+ def to_native_path_windows(path: PathLike) -> str:
path = str(path)
return path.replace("/", "\\")
--
2.35.6

View File

@@ -13,6 +13,8 @@ PYPI_PACKAGE = "GitPython"
inherit pypi python_setuptools_build_meta
SRC_URI += "file://CVE-2026-42284.patch \
file://CVE-2026-44243_p1.patch \
file://CVE-2026-44243_p2.patch \
"
SRC_URI[sha256sum] = "2d99869e0fef71a73cbd242528105af1d6c1b108c60dfabd994bf292f76c3ceb"