Skip to content

Commit dfd008b

Browse files
Merge PR "[AUTO-CHERRYPICK] Patch python-virtualenv for CVE-2026-8643 - branch 3.0-dev" microsoft#17768
Co-authored-by: Aditya Singh <v-aditysing@microsoft.com>
1 parent 23a6082 commit dfd008b

3 files changed

Lines changed: 128 additions & 1 deletion

File tree

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
From 7f85b4d60f6efc690baf11266650eaba0b1d6c46 Mon Sep 17 00:00:00 2001
2+
From: Damian Shaw <damian.peter.shaw@gmail.com>
3+
Date: Mon, 18 May 2026 23:04:43 -0400
4+
Subject: [PATCH] Reject entry point names that escape scripts dir
5+
6+
Upstream Patch Reference: https://patch-diff.githubusercontent.com/raw/pypa/pip/pull/14000.patch
7+
---
8+
pip/_internal/operations/install/wheel.py | 26 ++++++++++++++++++++---
9+
1 file changed, 23 insertions(+), 3 deletions(-)
10+
11+
diff --git a/pip/_internal/operations/install/wheel.py b/pip/_internal/operations/install/wheel.py
12+
index aef42aa..84ae542 100644
13+
--- a/pip/_internal/operations/install/wheel.py
14+
+++ b/pip/_internal/operations/install/wheel.py
15+
@@ -405,17 +405,37 @@ class MissingCallableSuffix(InstallationError):
16+
)
17+
18+
19+
-def _raise_for_invalid_entrypoint(specification: str) -> None:
20+
+def _script_within_dir(name: str, scripts_dir: str) -> bool:
21+
+ """Return whether script ``name`` resolves to a path inside the ``scripts_dir``.
22+
+
23+
+ distlib joins the entry point name onto the scripts directory, so a name
24+
+ with path separators or ``..`` components can resolve elsewhere.
25+
+ """
26+
+ root = os.path.normpath(scripts_dir)
27+
+ dest = os.path.normpath(os.path.join(scripts_dir, name))
28+
+ return dest.startswith(root + os.sep)
29+
+
30+
+
31+
+def _raise_for_invalid_entrypoint(specification: str, scripts_dir: str) -> None:
32+
entry = get_export_entry(specification)
33+
- if entry is not None and entry.suffix is None:
34+
+ if entry is None:
35+
+ return
36+
+
37+
+ if entry.suffix is None:
38+
raise MissingCallableSuffix(str(entry))
39+
40+
+ if not _script_within_dir(entry.name, scripts_dir):
41+
+ raise InstallationError(
42+
+ f"Invalid script entry point name {entry.name!r}: the script "
43+
+ f"would be installed outside the scripts directory ({scripts_dir})."
44+
+ )
45+
+
46+
47+
class PipScriptMaker(ScriptMaker):
48+
def make(
49+
self, specification: str, options: Optional[Dict[str, Any]] = None
50+
) -> List[str]:
51+
- _raise_for_invalid_entrypoint(specification)
52+
+ _raise_for_invalid_entrypoint(specification, self.target_dir)
53+
return super().make(specification, options)
54+
55+
56+
--
57+
2.45.4
58+
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
From 7f85b4d60f6efc690baf11266650eaba0b1d6c46 Mon Sep 17 00:00:00 2001
2+
From: Damian Shaw <damian.peter.shaw@gmail.com>
3+
Date: Mon, 18 May 2026 23:04:43 -0400
4+
Subject: [PATCH] Reject entry point names that escape scripts dir
5+
6+
Upstream Patch Reference: https://patch-diff.githubusercontent.com/raw/pypa/pip/pull/14000.patch
7+
---
8+
pip/_internal/operations/install/wheel.py | 26 ++++++++++++++++++++---
9+
1 file changed, 23 insertions(+), 3 deletions(-)
10+
11+
diff --git a/pip/_internal/operations/install/wheel.py b/pip/_internal/operations/install/wheel.py
12+
index 2724f15..ec2faaa 100644
13+
--- a/pip/_internal/operations/install/wheel.py
14+
+++ b/pip/_internal/operations/install/wheel.py
15+
@@ -397,11 +397,31 @@ class MissingCallableSuffix(InstallationError):
16+
)
17+
18+
19+
-def _raise_for_invalid_entrypoint(specification: str) -> None:
20+
+def _script_within_dir(name: str, scripts_dir: str) -> bool:
21+
+ """Return whether script ``name`` resolves to a path inside the ``scripts_dir``.
22+
+
23+
+ distlib joins the entry point name onto the scripts directory, so a name
24+
+ with path separators or ``..`` components can resolve elsewhere.
25+
+ """
26+
+ root = os.path.normpath(scripts_dir)
27+
+ dest = os.path.normpath(os.path.join(scripts_dir, name))
28+
+ return dest.startswith(root + os.sep)
29+
+
30+
+
31+
+def _raise_for_invalid_entrypoint(specification: str, scripts_dir: str) -> None:
32+
entry = get_export_entry(specification)
33+
- if entry is not None and entry.suffix is None:
34+
+ if entry is None:
35+
+ return
36+
+
37+
+ if entry.suffix is None:
38+
raise MissingCallableSuffix(str(entry))
39+
40+
+ if not _script_within_dir(entry.name, scripts_dir):
41+
+ raise InstallationError(
42+
+ f"Invalid script entry point name {entry.name!r}: the script "
43+
+ f"would be installed outside the scripts directory ({scripts_dir})."
44+
+ )
45+
+
46+
47+
class PipScriptMaker(ScriptMaker):
48+
# Override distlib's default script template with one that
49+
@@ -420,7 +440,7 @@ class PipScriptMaker(ScriptMaker):
50+
def make(
51+
self, specification: str, options: dict[str, Any] | None = None
52+
) -> list[str]:
53+
- _raise_for_invalid_entrypoint(specification)
54+
+ _raise_for_invalid_entrypoint(specification, self.target_dir)
55+
return super().make(specification, options)
56+
57+
58+
--
59+
2.45.4
60+

SPECS/python-virtualenv/python-virtualenv.spec

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Summary: Virtual Python Environment builder
22
Name: python-virtualenv
33
Version: 20.36.1
4-
Release: 4%{?dist}
4+
Release: 5%{?dist}
55
License: MIT
66
Vendor: Microsoft Corporation
77
Distribution: Azure Linux
@@ -18,6 +18,8 @@ Patch1005: CVE-2026-3219v0.patch
1818
Patch1006: CVE-2026-3219v1.patch
1919
Patch1007: CVE-2026-6357v0.patch
2020
Patch1008: CVE-2026-6357v1.patch
21+
Patch1009: CVE-2026-8643v0.patch
22+
Patch1010: CVE-2026-8643v1.patch
2123
BuildArch: noarch
2224

2325
%description
@@ -71,6 +73,8 @@ virtualenv-20.36.1/src/virtualenv/seed/wheels/embed/pip-25.0.1-py3-none-any.whl/
7173
virtualenv-20.36.1/src/virtualenv/seed/wheels/embed/pip-25.0.1-py3-none-any.whl/pip/_internal/commands/list.py
7274
virtualenv-20.36.1/src/virtualenv/seed/wheels/embed/pip-25.0.1-py3-none-any.whl/pip/_internal/self_outdated_check.py for CVE-2026-6357"
7375
patch -p1 -d unpacked_pip-25.0.1-py3-none-any < %{PATCH1007}
76+
echo "Manually Patching virtualenv-20.36.1/src/virtualenv/seed/wheels/embed/pip-25.0.1-py3-none-any.whl/pip/_internal/operations/install/wheel.py for CVE-2026-8643"
77+
patch -p1 -d unpacked_pip-25.0.1-py3-none-any < %{PATCH1009}
7478
# Remove the original file
7579
rm -f src/virtualenv/seed/wheels/embed/pip-25.0.1-py3-none-any.whl
7680
# After patching, re-zip the contents back into a .whl
@@ -95,6 +99,8 @@ virtualenv-20.36.1/src/virtualenv/seed/wheels/embed/pip-25.3-py3-none-any.whl/pi
9599
virtualenv-20.36.1/src/virtualenv/seed/wheels/embed/pip-25.3-py3-none-any.whl/pip/_internal/commands/list.py
96100
virtualenv-20.36.1/src/virtualenv/seed/wheels/embed/pip-25.3-py3-none-any.whl/pip/_internal/self_outdated_check.py for CVE-2026-6357"
97101
patch -p1 -d unpacked_pip-25.3-py3-none-any < %{PATCH1008}
102+
echo "Manually Patching virtualenv-20.36.1/src/virtualenv/seed/wheels/embed/pip-25.3-py3-none-any.whl/pip/_internal/operations/install/wheel.py for CVE-2026-8643"
103+
patch -p1 -d unpacked_pip-25.3-py3-none-any < %{PATCH1010}
98104
rm -f src/virtualenv/seed/wheels/embed/pip-25.3-py3-none-any.whl
99105
pushd unpacked_pip-25.3-py3-none-any
100106
zip -r ../src/virtualenv/seed/wheels/embed/pip-25.3-py3-none-any.whl *
@@ -157,6 +163,9 @@ tox -e py
157163
%{_bindir}/virtualenv
158164

159165
%changelog
166+
* Wed Jun 17 2026 Aditya Singh <v-aditysing@microsoft.com> - 20.36.1-5
167+
- Patch for CVE-2026-8643
168+
160169
* Mon May 11 2026 BinduSri Adabala <v-badabala@microsoft.com> - 20.36.1-4
161170
- Patch for CVE-2026-6357
162171

0 commit comments

Comments
 (0)