diff --git a/meta/recipes-devtools/python/python3-git/CVE-2026-44243_p1.patch b/meta/recipes-devtools/python/python3-git/CVE-2026-44243_p1.patch new file mode 100644 index 0000000000..6c9af542b5 --- /dev/null +++ b/meta/recipes-devtools/python/python3-git/CVE-2026-44243_p1.patch @@ -0,0 +1,136 @@ +From fcd8d016816696780c0dc96dacbe48fc10df80f6 Mon Sep 17 00:00:00 2001 +From: "GPT 5.5" +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 +(cherry picked from commit 25ba54dd3fb374b8fade7de4be1ac2ac84722190) +Signed-off-by: Darsh Kelaiya +--- + 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 diff --git a/meta/recipes-devtools/python/python3-git/CVE-2026-44243_p2.patch b/meta/recipes-devtools/python/python3-git/CVE-2026-44243_p2.patch new file mode 100644 index 0000000000..e14c284d12 --- /dev/null +++ b/meta/recipes-devtools/python/python3-git/CVE-2026-44243_p2.patch @@ -0,0 +1,86 @@ +From 2d1f681978b51ffff0db57cf89b0bcd6bffc7418 Mon Sep 17 00:00:00 2001 +From: "GPT 5.5" +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 +(cherry picked from commit 4af8463cca31c2369312fcaa5309dfc30756c7b6) +Signed-off-by: Darsh Kelaiya +--- + 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 diff --git a/meta/recipes-devtools/python/python3-git_3.1.42.bb b/meta/recipes-devtools/python/python3-git_3.1.42.bb index c294b23112..99f31791bd 100644 --- a/meta/recipes-devtools/python/python3-git_3.1.42.bb +++ b/meta/recipes-devtools/python/python3-git_3.1.42.bb @@ -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"