new file mode 100644
@@ -0,0 +1,77 @@
+From 47e0d430af6885ceeaa38a8c5517efac872b70b4 Mon Sep 17 00:00:00 2001
+From: Byron <sebastian.thiel@icloud.com>
+Date: Tue, 11 Aug 2026 14:18:25 +0200
+Subject: [PATCH] fix: parse actor identities without regular expressions
+
+<!-- agent -->
+GHSA-g5vv-9gxw-82hx reports quadratic backtracking when an actor
+identity contains a long unterminated email delimiter.
+
+Add a regression that exercises a 20,000-character malformed identity,
+then replace both actor regexes with direct delimiter scans following
+Git's first-opening, first-closing delimiter behavior. Keep GitPython's
+whole-string fallback when either delimiter is absent.
+
+Reference Git baseline cf5497b14c5a24f10c13f7e0ee85cb95
+ident.c::split_ident_line and its invalid-committer cases in
+t/t9300-fast-import.sh. Also reference gix-actor's signature decoder and
+lenient identity tests.
+
+CVE: CVE-2026-87819
+Upstream-Status: Backport [https://github.com/gitpython-developers/GitPython/commit/751473a5f3221d6f989291cbebcc404353fd3ba8]
+
+Backport Changes:
+- Omitted test/test_actor.py because the current PyPI source
+ archive does not include the test suite and the python3-git
+ recipe does not run it.
+
+Assisted-by: GPT 5.6
+Co-authored-by: GPT 5.6 <codex@openai.com>
+(cherry picked from commit 751473a5f3221d6f989291cbebcc404353fd3ba8)
+Signed-off-by: Yogita Urade <yurade@cisco.com>
+---
+ git/util.py | 24 ++++++++----------------
+ 1 file changed, 8 insertions(+), 16 deletions(-)
+
+diff --git a/git/util.py b/git/util.py
+index 9619937c..9a698e6d 100644
+--- a/git/util.py
++++ b/git/util.py
+@@ -772,10 +772,6 @@ class Actor:
+ committers and authors or anything with a name and an email as mentioned in the git
+ log entries."""
+
+- # PRECOMPILED REGEX
+- name_only_regex = re.compile(r"<(.*)>")
+- name_email_regex = re.compile(r"(.*) <(.*?)>")
+-
+ # ENVIRONMENT VARIABLES
+ # These are read when creating new commits.
+ env_author_name = "GIT_AUTHOR_NAME"
+@@ -820,18 +816,14 @@ class Actor:
+ :return:
+ :class:`Actor`
+ """
+- m = cls.name_email_regex.search(string)
+- if m:
+- name, email = m.groups()
+- return Actor(name, email)
+- else:
+- m = cls.name_only_regex.search(string)
+- if m:
+- return Actor(m.group(1), None)
+- # Assume the best and use the whole string as name.
+- return Actor(string, None)
+- # END special case name
+- # END handle name/email matching
++ line = string.partition("\n")[0]
++ left_bracket = line.find("<")
++ right_bracket = line.find(">", left_bracket + 1)
++ if left_bracket >= 0 and right_bracket >= 0:
++ return Actor(line[:left_bracket].rstrip(), line[left_bracket + 1 : right_bracket])
++
++ # Assume the best and use the whole string as name.
++ return Actor(string, None)
+
+ @classmethod
+ def _main_actor(
new file mode 100644
@@ -0,0 +1,139 @@
+From 0d63f66a673cfcad25a1fd85f56177d19a1b6547 Mon Sep 17 00:00:00 2001
+From: Byron <sebastian.thiel@icloud.com>
+Date: Fri, 28 Aug 2026 08:37:50 +0200
+Subject: [PATCH] fix: restore Actor.name_email_regex (#2220)
+
+<!-- agent -->
+GitPython 3.1.60 removed the Actor.name_email_regex class attribute while
+replacing internal actor parsing, which broke downstream consumers such as
+python-semantic-release.
+
+Bring back the historical compiled pattern for downstream compatibility,
+but emit DeprecationWarning whenever the class member is accessed. The warning
+explains its quadratic behavior on long malformed strings and points callers to
+the public Actor(name, email) constructor when fields are separate, or direct
+string parsing when they are not.
+
+Assisted-by: GPT 5.6
+Co-authored-by: GPT 5.6 <codex@openai.com>
+
+Add public Actor.from_string constructor (#2220)
+
+Promote the existing actor identity parser to Actor.from_string while retaining _from_string as a compatibility alias. Point the name_email_regex deprecation warning to the new public constructor or Actor(name, email).
+
+Validation:
+- actor-related test/test_actor.py and test/test_util.py cases: 12 passed
+- ruff check and format checks passed
+- basedpyright git/util.py: no errors
+
+Co-authored-by: Codex GPT-5 <codex@openai.com>
+
+Address review feedback about Actor subclasses
+
+Review feedback: Actor.from_string() should preserve the class on which the public classmethod is called instead of always returning a base Actor.
+
+Construct through cls on both parsing paths and cover subclass construction directly.
+
+Validation:
+- actor-related test/test_actor.py and test/test_util.py cases: 13 passed
+- ruff check and format checks passed
+- basedpyright git/util.py: no errors
+
+Address review feedback about constructor typing
+
+Review feedback: Actor.from_string() constructs subclasses at runtime but its Actor return annotation prevents type checkers from preserving subclass-specific members.
+
+Use the project existing Python 3.7-compatible bound TypeVar pattern so the declared return type follows cls.
+
+Validation:
+- actor-related test/test_actor.py and test/test_util.py cases: 13 passed
+- ruff check and format checks passed
+- basedpyright git/util.py: no errors
+
+CVE: CVE-2026-87819
+Upstream-Status: Backport [https://github.com/gitpython-developers/GitPython/commit/bc63b027e2fc737e2ec0222bfa764e1aa76a427f]
+
+Backport Changes:
+- Omitted test/test_actor.py because the current PyPI source archive
+ does not include the test suite and the python3-git recipe does not
+ run it.
+
+Co-authored-by: Codex GPT-5 <codex@openai.com>
+(cherry picked from commit bc63b027e2fc737e2ec0222bfa764e1aa76a427f)
+Signed-off-by: Yogita Urade <yurade@cisco.com>
+---
+ git/util.py | 26 +++++++++++++++++++++++---
+ 1 file changed, 23 insertions(+), 3 deletions(-)
+
+diff --git a/git/util.py b/git/util.py
+index 9a698e6d..16cd25ef 100644
+--- a/git/util.py
++++ b/git/util.py
+@@ -80,6 +80,7 @@ from typing import (
+ Sequence,
+ Tuple,
+ TYPE_CHECKING,
++ Type,
+ TypeVar,
+ Union,
+ cast,
+@@ -108,6 +109,7 @@ from git.types import (
+
+ T_IterableObj = TypeVar("T_IterableObj", bound=Union["IterableObj", "Has_id_attribute"], covariant=True)
+ # So IterableList[Head] is subtype of IterableList[IterableObj].
++T_Actor = TypeVar("T_Actor", bound="Actor")
+
+ _logger = logging.getLogger(__name__)
+
+@@ -767,11 +769,27 @@ class CallableRemoteProgress(RemoteProgress):
+ self._callable(*args, **kwargs)
+
+
++class _DeprecatedActorNameEmailRegex:
++ _pattern = re.compile(r"(.*) <(.*?)>")
++
++ def __get__(self, _instance: Any, _owner: Any) -> Pattern[str]:
++ warnings.warn(
++ "Actor.name_email_regex is deprecated and will be removed in GitPython 4.0.0 because searching long "
++ "malformed strings with it can take quadratic time. Use Actor.from_string() to parse actor identities, "
++ "or Actor(name, email) when the fields are already separate.",
++ DeprecationWarning,
++ stacklevel=2,
++ )
++ return self._pattern
++
++
+ class Actor:
+ """Actors hold information about a person acting on the repository. They can be
+ committers and authors or anything with a name and an email as mentioned in the git
+ log entries."""
+
++ name_email_regex = _DeprecatedActorNameEmailRegex()
++
+ # ENVIRONMENT VARIABLES
+ # These are read when creating new commits.
+ env_author_name = "GIT_AUTHOR_NAME"
+@@ -805,7 +823,7 @@ class Actor:
+ return '<git.Actor "%s <%s>">' % (self.name, self.email)
+
+ @classmethod
+- def _from_string(cls, string: str) -> "Actor":
++ def from_string(cls: Type[T_Actor], string: str) -> T_Actor:
+ """Create an :class:`Actor` from a string.
+
+ :param string:
+@@ -820,10 +838,12 @@ class Actor:
+ left_bracket = line.find("<")
+ right_bracket = line.find(">", left_bracket + 1)
+ if left_bracket >= 0 and right_bracket >= 0:
+- return Actor(line[:left_bracket].rstrip(), line[left_bracket + 1 : right_bracket])
++ return cls(line[:left_bracket].rstrip(), line[left_bracket + 1 : right_bracket])
+
+ # Assume the best and use the whole string as name.
+- return Actor(string, None)
++ return cls(string, None)
++
++ _from_string = from_string
+
+ @classmethod
+ def _main_actor(
@@ -49,6 +49,8 @@ SRC_URI += "file://CVE-2026-42284.patch \
file://CVE-2026-78675.patch \
file://CVE-2026-87817.patch \
file://CVE-2026-87818.patch \
+ file://CVE-2026-87819_p1.patch \
+ file://CVE-2026-87819_p2.patch \
"
SRC_URI[sha256sum] = "35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c"
This patch applies the upstream fix as referenced in [3], using the commit shown in [1] and [2]. [1] https://github.com/gitpython-developers/GitPython/commit/751473a5f3221d6f989291cbebcc404353fd3ba8 [2] https://github.com/gitpython-developers/GitPython/commit/bc63b027e2fc737e2ec0222bfa764e1aa76a427f [3] https://nvd.nist.gov/vuln/detail/CVE-2026-87819 Signed-off-by: Yogita Urade <yurade@cisco.com> --- .../python3-git/CVE-2026-87819_p1.patch | 77 ++++++++++ .../python3-git/CVE-2026-87819_p2.patch | 139 ++++++++++++++++++ .../python/python3-git_3.1.43.bb | 2 + 3 files changed, 218 insertions(+) create mode 100644 meta/recipes-devtools/python/python3-git/CVE-2026-87819_p1.patch create mode 100644 meta/recipes-devtools/python/python3-git/CVE-2026-87819_p2.patch