new file mode 100644
@@ -0,0 +1,35 @@
+From a82b22c137622eb76112d5ec04e86b246e57eab3 Mon Sep 17 00:00:00 2001
+From: Byron <sebastian.thiel@icloud.com>
+Date: Tue, 4 Aug 2026 11:07:02 +0200
+Subject: [PATCH] Initialize submodule repository before handled failures
+
+Direct recursive updates with keep_going could swallow an invalid-name
+validation error and then access mrepo before assignment. Initialize
+mrepo before validation so recursion is safely skipped.
+
+CVE: CVE-2026-76222
+Upstream-Status: Backport [https://github.com/gitpython-developers/GitPython/commit/b324c831cbc02c82b99c18113b622d03539d23cd]
+
+Backport Changes:
+- Omitted `test/test_submodule.py` because the PyPI source archive omits
+ tests, which are outside this recipe's test surface.
+- Omitted `.basedpyright/baseline.json` because it is development-only
+ static-analysis metadata absent from the source archive.
+
+Assisted-by: GPT 5.6
+Co-authored-by: GPT 5.6 <codex@openai.com>
+(cherry picked from commit b324c831cbc02c82b99c18113b622d03539d23cd)
+Signed-off-by: Yogita Urade <yurade@cisco.com>
+---
+ git/objects/submodule/base.py | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/git/objects/submodule/base.py b/git/objects/submodule/base.py
+index ec0a534f..45fc4551 100644
+--- a/git/objects/submodule/base.py
++++ b/git/objects/submodule/base.py
+@@ -640,3 +640 @@ class Submodule(IndexObject, TraversableIterableObj):
+- # To keep things plausible in dry-run mode.
+- if dry_run:
+- mrepo = None
++ mrepo = None
new file mode 100644
@@ -0,0 +1,123 @@
+From 190b90a1932cb548b0b95f5c2751377012c37d42 Mon Sep 17 00:00:00 2001
+From: Byron <sebastian.thiel@icloud.com>
+Date: Sat, 1 Aug 2026 04:47:40 +0200
+Subject: [PATCH 27/38] Validate submodule names before filesystem operations
+
+<!-- agent -->
+Submodule names read from .gitmodules can influence the separate Git directory
+path. Reject empty names, absolute or drive-qualified names, and parent
+components with either path separator.
+
+Validate before constructing module paths and before opening or mutating
+existing checkouts, so a repository initialized by an older vulnerable version
+cannot bypass the guard. Validate programmatic add and rename inputs before
+making changes as well.
+
+Advisory: GHSA-hmq2-w58f-27jc
+
+
+CVE: CVE-2026-76222
+Upstream-Status: Backport [https://github.com/gitpython-developers/GitPython/commit/e4b8e7d026ca6abb4cf604f8e77093432ce23c06]
+
+Backport Changes:
+- Omit upstream regression test changes because the Scarthgap PyPI source archive does not include its test suite.
+
+Assisted-by: GPT 5.6
+Co-authored-by: GPT 5.6 <codex@openai.com>
+(cherry picked from commit e4b8e7d026ca6abb4cf604f8e77093432ce23c06)
+Signed-off-by: Yogita Urade <yurade@cisco.com>
+
+---
+ git/objects/submodule/base.py | 23 ++++++++++++++++++++++-
+ 1 file changed, 22 insertions(+), 1 deletion(-)
+
+diff --git a/git/objects/submodule/base.py b/git/objects/submodule/base.py
+index 4fe2ff3f..84d6bcdc 100644
+--- a/git/objects/submodule/base.py
++++ b/git/objects/submodule/base.py
+@@ -4,6 +4,7 @@
+ import gc
+ from io import BytesIO
+ import logging
++import ntpath
+ import os
+ import os.path as osp
+ import stat
+@@ -267,10 +268,21 @@ class Submodule(IndexObject, TraversableIterableObj):
+ parser.set_submodule(self)
+ return SectionConstraint(parser, sm_section(self.name))
+
++ @classmethod
++ def _validated_name(cls, name: str) -> str:
++ if (
++ not name
++ or name.startswith(("/", "\\"))
++ or ntpath.splitdrive(name)[0]
++ or ".." in name.replace("\\", "/").split("/")
++ ):
++ raise ValueError("Invalid submodule name %r" % name)
++ return name
++
+ @classmethod
+ def _module_abspath(cls, parent_repo: "Repo", path: PathLike, name: str) -> PathLike:
+ if cls._need_gitfile_submodules(parent_repo.git):
+- return osp.join(parent_repo.git_dir, "modules", name)
++ return osp.join(parent_repo.git_dir, "modules", cls._validated_name(name))
+ if parent_repo.working_tree_dir:
+ return osp.join(parent_repo.working_tree_dir, path)
+ raise NotADirectoryError()
+@@ -430,6 +442,7 @@ class Submodule(IndexObject, TraversableIterableObj):
+ raise InvalidGitRepositoryError("Cannot add submodules to bare repositories")
+ # END handle bare repos
+
++ cls._validated_name(name)
+ path = cls._to_relative_path(repo, path)
+
+ # Ensure we never put backslashes into the URL, as some operating systems
+@@ -629,6 +642,8 @@ class Submodule(IndexObject, TraversableIterableObj):
+ # END init mrepo
+
+ try:
++ self._validated_name(self.name)
++
+ # ENSURE REPO IS PRESENT AND UP-TO-DATE
+ #######################################
+ try:
+@@ -880,6 +895,7 @@ class Submodule(IndexObject, TraversableIterableObj):
+ raise ValueError("You must specify to move at least the module or the configuration of the submodule")
+ # END handle input
+
++ self._validated_name(self.name)
+ module_checkout_path = self._to_relative_path(self.repo, module_path)
+
+ # VERIFY DESTINATION
+@@ -1002,6 +1018,7 @@ class Submodule(IndexObject, TraversableIterableObj):
+ raise ValueError("Need to specify to delete at least the module, or the configuration")
+ # END handle parameters
+
++ self._validated_name(self.name)
+ # Recursively remove children of this submodule.
+ nc = 0
+ for csm in self.children():
+@@ -1211,6 +1228,9 @@ class Submodule(IndexObject, TraversableIterableObj):
+ if self.name == new_name:
+ return self
+
++ self._validated_name(self.name)
++ self._validated_name(new_name)
++
+ # .git/config
+ with self.repo.config_writer() as pw:
+ # As we ourselves didn't write anything about submodules into the parent .git/config,
+@@ -1254,6 +1274,7 @@ class Submodule(IndexObject, TraversableIterableObj):
+ :raise InvalidGitRepositoryError: If a repository was not available. This could
+ also mean that it was not yet initialized.
+ """
++ self._validated_name(self.name)
+ module_checkout_abspath = self.abspath
+ try:
+ repo = git.Repo(module_checkout_abspath)
+--
+2.35.6
+(cherry picked from commit e4b8e7d026ca6abb4cf604f8e77093432ce23c06)
+Signed-off-by: Yogita Urade <yurade@cisco.com>
new file mode 100644
@@ -0,0 +1,49 @@
+From df2835724f8f92bc0a9efed691e14c8bdf58a6dc Mon Sep 17 00:00:00 2001
+From: Byron <sebastian.thiel@icloud.com>
+Date: Tue, 4 Aug 2026 10:08:41 +0200
+Subject: [PATCH 28/38] Validate submodule names on every module path branch
+
+<!-- agent -->
+_module_abspath only validated names when Git used separate gitfile
+submodule directories, so legacy Git behavior could accept the same invalid
+name. Validate before selecting the Git-version-dependent path branch and
+cover the legacy branch explicitly.
+
+Git baseline: submodule.c at 883a47ef6496c96a5d6132ed8c87fcd44ebf8d1a
+validates submodule paths before filesystem operations.
+
+
+CVE: CVE-2026-76222
+Upstream-Status: Backport [https://github.com/gitpython-developers/GitPython/commit/4299c990e1ca21896f9485277caf7bb0ae5b404c]
+
+Backport Changes:
+- Omit upstream regression test changes because the Scarthgap PyPI source archive does not include its test suite.
+
+Assisted-by: GPT 5.6
+Co-authored-by: GPT 5.6 <codex@openai.com>
+(cherry picked from commit 4299c990e1ca21896f9485277caf7bb0ae5b404c)
+Signed-off-by: Yogita Urade <yurade@cisco.com>
+
+---
+ git/objects/submodule/base.py | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/git/objects/submodule/base.py b/git/objects/submodule/base.py
+index 84d6bcdc..09a784e1 100644
+--- a/git/objects/submodule/base.py
++++ b/git/objects/submodule/base.py
+@@ -281,8 +281,9 @@ class Submodule(IndexObject, TraversableIterableObj):
+
+ @classmethod
+ def _module_abspath(cls, parent_repo: "Repo", path: PathLike, name: str) -> PathLike:
++ name = cls._validated_name(name)
+ if cls._need_gitfile_submodules(parent_repo.git):
+- return osp.join(parent_repo.git_dir, "modules", cls._validated_name(name))
++ return osp.join(parent_repo.git_dir, "modules", name)
+ if parent_repo.working_tree_dir:
+ return osp.join(parent_repo.working_tree_dir, path)
+ raise NotADirectoryError()
+--
+2.35.6
+(cherry picked from commit 4299c990e1ca21896f9485277caf7bb0ae5b404c)
+Signed-off-by: Yogita Urade <yurade@cisco.com>
@@ -40,6 +40,9 @@ SRC_URI += " file://CVE-2026-42284.patch \
file://CVE-2026-76219.patch \
file://CVE-2026-76218.patch \
file://CVE-2026-76217.patch \
+ file://CVE-2026-76222_p1.patch \
+ file://CVE-2026-76222-regression.patch \
+ file://CVE-2026-76222_p2.patch \
"
SRC_URI[sha256sum] = "2d99869e0fef71a73cbd242528105af1d6c1b108c60dfabd994bf292f76c3ceb"
This patch applies the upstream fix as referenced in [4], using the commit shown in [1], regression fix in [2] and follow-up fix in [3]. [1] https://github.com/gitpython-developers/GitPython/commit/e4b8e7d026ca6abb4cf604f8e77093432ce23c06 [2] https://github.com/gitpython-developers/GitPython/commit/b324c831cbc02c82b99c18113b622d03539d23cd [3] https://github.com/gitpython-developers/GitPython/commit/4299c990e1ca21896f9485277caf7bb0ae5b404c [4] https://nvd.nist.gov/vuln/detail/CVE-2026-76222 Signed-off-by: Yogita Urade <yurade@cisco.com> --- .../CVE-2026-76222-regression.patch | 35 +++++ .../python3-git/CVE-2026-76222_p1.patch | 123 ++++++++++++++++++ .../python3-git/CVE-2026-76222_p2.patch | 49 +++++++ .../python/python3-git_3.1.42.bb | 3 + 4 files changed, 210 insertions(+) create mode 100644 meta/recipes-devtools/python/python3-git/CVE-2026-76222-regression.patch create mode 100644 meta/recipes-devtools/python/python3-git/CVE-2026-76222_p1.patch create mode 100644 meta/recipes-devtools/python/python3-git/CVE-2026-76222_p2.patch