From: Facundo Tuesca <facundo.tuesca@trailofbits.com>
Date: Tue, 5 Sep 2023 09:51:50 +0200
Subject: Fix CVE-2023-41040

This change adds a check during reference resolving to see if it
contains an up-level reference ('..'). If it does, it raises an
exception.

This fixes CVE-2023-41040, which allows an attacker to access files
outside the repository's directory.

Origin: https://github.com/gitpython-developers/GitPython/commit/64ebb9fcdfbe48d5d61141a557691fd91f1e88d6
Origin: https://github.com/gitpython-developers/GitPython/commit/65b8c6a2ccacdf26e751cd3bc3c5a7c9e5796b56
Bug: https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-cwvm-v4w8-q58c
Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2023-41040
---
 git/refs/symbolic.py  |  2 ++
 git/test/test_refs.py | 15 +++++++++++++++
 2 files changed, 17 insertions(+)

--- a/git/refs/symbolic.py
+++ b/git/refs/symbolic.py
@@ -168,6 +168,8 @@
         """Return: (str(sha), str(target_ref_path)) if available, the sha the file at
         rela_path points to, or None. target_ref_path is the reference we
         point to, or None"""
+        if ".." in str(ref_path):
+            raise ValueError(f"Invalid reference '{ref_path}'")
         tokens: Union[None, List[str], Tuple[str, str]] = None
         repodir = _git_dir(repo, ref_path)
         try:
--- a/test/test_refs.py
+++ b/test/test_refs.py
@@ -5,6 +5,7 @@
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 
 from itertools import chain
+from pathlib import Path
 
 from git import (
     Reference,
@@ -19,9 +20,11 @@
 from git.objects.tag import TagObject
 from test.lib import TestBase, with_rw_repo
 from git.util import Actor
+from gitdb.exc import BadName
 
 import git.refs as refs
 import os.path as osp
+import tempfile
 
 
 class TestRefs(TestBase):
@@ -595,3 +598,15 @@
 
     def test_reflog(self):
         assert isinstance(self.rorepo.heads.master.log(), RefLog)
+
+    def test_refs_outside_repo(self):
+        # Create a file containing a valid reference outside the repository. Attempting
+        # to access it should raise an exception, due to it containing a parent directory
+        # reference ('..'). This tests for CVE-2023-41040.
+        git_dir = Path(self.rorepo.git_dir)
+        repo_parent_dir = git_dir.parent.parent
+        with tempfile.NamedTemporaryFile(dir=repo_parent_dir) as ref_file:
+            ref_file.write(b"91b464cd624fe22fbf54ea22b85a7e5cca507cfe")
+            ref_file.flush()
+            ref_file_name = Path(ref_file.name).name
+            self.assertRaises(BadName, self.rorepo.commit, "../../%s" % ref_file_name)
