File CVE-2026-34591.patch of Package python-poetry.43616

From ed59537ac3709cfbdbf95d957de801c13872991a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Randy=20D=C3=B6ring?=
 <30527984+radoering@users.noreply.github.com>
Date: Sun, 29 Mar 2026 10:24:17 +0200
Subject: [PATCH] installer: fix path traversal (#10792)

---
 src/poetry/installation/wheel_installer.py |  9 +++-
 tests/installation/test_wheel_installer.py | 48 ++++++++++++++++++++++
 2 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/src/poetry/installation/wheel_installer.py b/src/poetry/installation/wheel_installer.py
index 57ee02d9a98..a086ca7361a 100644
--- a/src/poetry/installation/wheel_installer.py
+++ b/src/poetry/installation/wheel_installer.py
@@ -44,7 +44,14 @@ def write_to_fs(
         from installer.utils import copyfileobj_with_hashing
         from installer.utils import make_file_executable
 
-        target_path = Path(self.scheme_dict[scheme]) / path
+        target_dir = Path(self.scheme_dict[scheme]).resolve()
+        target_path = (target_dir / path).resolve()
+
+        if not target_path.is_relative_to(target_dir):
+            raise ValueError(
+                f"Attempting to write {path} outside of the target directory"
+            )
+
         if target_path.exists():
             # Contrary to the base library we don't raise an error here since it can
             # break pkgutil-style and pkg_resource-style namespace packages.
diff --git a/tests/installation/test_wheel_installer.py b/tests/installation/test_wheel_installer.py
index 98e3f4cf97e..33e95dd970a 100644
--- a/tests/installation/test_wheel_installer.py
+++ b/tests/installation/test_wheel_installer.py
@@ -81,3 +81,51 @@ def test_enable_bytecode_compilation(
         assert not list(cache_dir.glob("*.opt-2.pyc"))
     else:
         assert not cache_dir.exists()
+
+
+def test_install_dir_is_symlink(tmp_path: Path, demo_wheel: Path) -> None:
+    target_dir = tmp_path / "target"
+    target_dir.mkdir()
+    symlink_dir = tmp_path / "symlink"
+    symlink_dir.symlink_to(target_dir, target_is_directory=True)
+
+    env = MockEnv(path=symlink_dir)
+
+    installer = WheelInstaller(env)
+    installer.install(demo_wheel)
+
+    assert (Path(env.paths["purelib"]) / "demo").exists()
+
+
+@pytest.fixture
+def wheel_with_path_traversal(tmp_path: Path) -> Path:
+    import zipfile
+
+    wheel = tmp_path / "traversal-0.1-py3-none-any.whl"
+    files = {
+        "traversal/__init__.py": b"",
+        "../../traversal.txt": b"",
+        "traversal-0.1.dist-info/WHEEL": (
+            b"Wheel-Version: 1.0\nRoot-Is-Purelib: true\nTag: py3-none-any\n"
+        ),
+        "traversal-0.1.dist-info/METADATA": (
+            b"Metadata-Version: 2.1\nName: traversal\nVersion: 0.1\n"
+        ),
+    }
+    files["traversal-0.1.dist-info/RECORD"] = (
+        "\n".join([f"{k},," for k in files] + ["traversal-0.1.dist-info/RECORD,,"])
+        + "\n"
+    ).encode()
+
+    with zipfile.ZipFile(wheel, "w") as z:
+        for k, v in files.items():
+            z.writestr(k, v)
+
+    return wheel
+
+
+def test_path_traversal(env: MockEnv, wheel_with_path_traversal: Path) -> None:
+    installer = WheelInstaller(env)
+    with pytest.raises(ValueError):
+        installer.install(wheel_with_path_traversal)
+    assert not (env.path.parent / "traversal.txt").exists()
openSUSE Build Service is sponsored by