Skip to content

Commit a799222

Browse files
[Medium] Patch python-virtualenv for CVE-2026-1703 & CVE-2026-24049 (#15983)
1 parent e468054 commit a799222

7 files changed

Lines changed: 247 additions & 1 deletion

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
From 4c651b70d60ed91b13663bcda9b3ed41748d0124 Mon Sep 17 00:00:00 2001
2+
From: Seth Michael Larson <seth@python.org>
3+
Date: Fri, 30 Jan 2026 09:49:11 -0600
4+
Subject: [PATCH] Use os.path.commonpath() instead of commonprefix()
5+
6+
Upstream Patch Reference: https://github.com/pypa/pip/commit/8e227a9be4faa9594e05d02ca05a413a2a4e7735.patch
7+
---
8+
news/+1ee322a1.bugfix.rst | 1 +
9+
pip/_internal/utils/unpacking.py | 2 +-
10+
2 files changed, 2 insertions(+), 1 deletion(-)
11+
create mode 100644 news/+1ee322a1.bugfix.rst
12+
13+
diff --git a/news/+1ee322a1.bugfix.rst b/news/+1ee322a1.bugfix.rst
14+
new file mode 100644
15+
index 0000000..edb1b32
16+
--- /dev/null
17+
+++ b/news/+1ee322a1.bugfix.rst
18+
@@ -0,0 +1 @@
19+
+Use a path-segment prefix comparison, not char-by-char.
20+
diff --git a/pip/_internal/utils/unpacking.py b/pip/_internal/utils/unpacking.py
21+
index 78b5c13..0b26525 100644
22+
--- a/pip/_internal/utils/unpacking.py
23+
+++ b/pip/_internal/utils/unpacking.py
24+
@@ -81,7 +81,7 @@ def is_within_directory(directory: str, target: str) -> bool:
25+
abs_directory = os.path.abspath(directory)
26+
abs_target = os.path.abspath(target)
27+
28+
- prefix = os.path.commonprefix([abs_directory, abs_target])
29+
+ prefix = os.path.commonpath([abs_directory, abs_target])
30+
return prefix == abs_directory
31+
32+
33+
--
34+
2.45.4
35+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
From 4c651b70d60ed91b13663bcda9b3ed41748d0124 Mon Sep 17 00:00:00 2001
2+
From: Seth Michael Larson <seth@python.org>
3+
Date: Fri, 30 Jan 2026 09:49:11 -0600
4+
Subject: [PATCH] Use os.path.commonpath() instead of commonprefix()
5+
6+
Upstream Patch Reference: https://github.com/pypa/pip/commit/8e227a9be4faa9594e05d02ca05a413a2a4e7735.patch
7+
---
8+
pip/_internal/utils/unpacking.py | 2 +-
9+
1 file changed, 1 insertion(+), 1 deletion(-)
10+
11+
diff --git a/pip/_internal/utils/unpacking.py b/pip/_internal/utils/unpacking.py
12+
index 875e30e..4abe64b 100644
13+
--- a/pip/_internal/utils/unpacking.py
14+
+++ b/pip/_internal/utils/unpacking.py
15+
@@ -82,7 +82,7 @@ def is_within_directory(directory: str, target: str) -> bool:
16+
abs_directory = os.path.abspath(directory)
17+
abs_target = os.path.abspath(target)
18+
19+
- prefix = os.path.commonprefix([abs_directory, abs_target])
20+
+ prefix = os.path.commonpath([abs_directory, abs_target])
21+
return prefix == abs_directory
22+
23+
24+
--
25+
2.45.4
26+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
From 4c651b70d60ed91b13663bcda9b3ed41748d0124 Mon Sep 17 00:00:00 2001
2+
From: Seth Michael Larson <seth@python.org>
3+
Date: Fri, 30 Jan 2026 09:49:11 -0600
4+
Subject: [PATCH] Use os.path.commonpath() instead of commonprefix()
5+
6+
Upstream Patch Reference: https://github.com/pypa/pip/commit/8e227a9be4faa9594e05d02ca05a413a2a4e7735.patch
7+
---
8+
news/+1ee322a1.bugfix.rst | 1 +
9+
pip/_internal/utils/unpacking.py | 2 +-
10+
2 files changed, 2 insertions(+), 1 deletion(-)
11+
create mode 100644 news/+1ee322a1.bugfix.rst
12+
13+
diff --git a/news/+1ee322a1.bugfix.rst b/news/+1ee322a1.bugfix.rst
14+
new file mode 100644
15+
index 0000000..edb1b32
16+
--- /dev/null
17+
+++ b/news/+1ee322a1.bugfix.rst
18+
@@ -0,0 +1 @@
19+
+Use a path-segment prefix comparison, not char-by-char.
20+
diff --git a/pip/_internal/utils/unpacking.py b/pip/_internal/utils/unpacking.py
21+
index 7252dc2..4ce2b15 100644
22+
--- a/pip/_internal/utils/unpacking.py
23+
+++ b/pip/_internal/utils/unpacking.py
24+
@@ -94,7 +94,7 @@ def is_within_directory(directory, target):
25+
abs_directory = os.path.abspath(directory)
26+
abs_target = os.path.abspath(target)
27+
28+
- prefix = os.path.commonprefix([abs_directory, abs_target])
29+
+ prefix = os.path.commonpath([abs_directory, abs_target])
30+
return prefix == abs_directory
31+
32+
33+
--
34+
2.45.4
35+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
From 7a7d2de96b22a9adf9208afcc9547e1001569fef Mon Sep 17 00:00:00 2001
2+
From: =?UTF-8?q?Alex=20Gr=C3=B6nholm?= <alex.gronholm@nextday.fi>
3+
Date: Thu, 22 Jan 2026 01:41:14 +0200
4+
Subject: [PATCH] Fixed security issue around wheel unpack (#675)
5+
6+
A maliciously crafted wheel could cause the permissions of a file outside the unpack tree to be altered.
7+
8+
Fixes CVE-2026-24049.
9+
Upstream Patch Reference: https://github.com/pypa/wheel/commit/7a7d2de96b22a9adf9208afcc9547e1001569fef.patch
10+
---
11+
setuptools/_vendor/wheel/cli/unpack.py | 4 ++--
12+
1 file changed, 2 insertions(+), 2 deletions(-)
13+
14+
diff --git a/setuptools/_vendor/wheel/cli/unpack.py b/setuptools/_vendor/wheel/cli/unpack.py
15+
index d48840e..83dc742 100644
16+
--- a/setuptools/_vendor/wheel/cli/unpack.py
17+
+++ b/setuptools/_vendor/wheel/cli/unpack.py
18+
@@ -19,12 +19,12 @@ def unpack(path: str, dest: str = ".") -> None:
19+
destination = Path(dest) / namever
20+
print(f"Unpacking to: {destination}...", end="", flush=True)
21+
for zinfo in wf.filelist:
22+
- wf.extract(zinfo, destination)
23+
+ target_path = Path(wf.extract(zinfo, destination))
24+
25+
# Set permissions to the same values as they were set in the archive
26+
# We have to do this manually due to
27+
# https://github.com/python/cpython/issues/59999
28+
permissions = zinfo.external_attr >> 16 & 0o777
29+
- destination.joinpath(zinfo.filename).chmod(permissions)
30+
+ target_path.chmod(permissions)
31+
32+
print("OK")
33+
--
34+
2.45.4
35+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
From 7a7d2de96b22a9adf9208afcc9547e1001569fef Mon Sep 17 00:00:00 2001
2+
From: =?UTF-8?q?Alex=20Gr=C3=B6nholm?= <alex.gronholm@nextday.fi>
3+
Date: Thu, 22 Jan 2026 01:41:14 +0200
4+
Subject: [PATCH] Fixed security issue around wheel unpack (#675)
5+
6+
A maliciously crafted wheel could cause the permissions of a file outside the unpack tree to be altered.
7+
8+
Fixes CVE-2026-24049.
9+
Upstream Patch Reference: https://github.com/pypa/wheel/commit/7a7d2de96b22a9adf9208afcc9547e1001569fef.patch
10+
---
11+
wheel/cli/unpack.py | 4 ++--
12+
1 file changed, 2 insertions(+), 2 deletions(-)
13+
14+
diff --git a/wheel/cli/unpack.py b/wheel/cli/unpack.py
15+
index d48840e..83dc742 100644
16+
--- a/wheel/cli/unpack.py
17+
+++ b/wheel/cli/unpack.py
18+
@@ -19,12 +19,12 @@ def unpack(path: str, dest: str = ".") -> None:
19+
destination = Path(dest) / namever
20+
print(f"Unpacking to: {destination}...", end="", flush=True)
21+
for zinfo in wf.filelist:
22+
- wf.extract(zinfo, destination)
23+
+ target_path = Path(wf.extract(zinfo, destination))
24+
25+
# Set permissions to the same values as they were set in the archive
26+
# We have to do this manually due to
27+
# https://github.com/python/cpython/issues/59999
28+
permissions = zinfo.external_attr >> 16 & 0o777
29+
- destination.joinpath(zinfo.filename).chmod(permissions)
30+
+ target_path.chmod(permissions)
31+
32+
print("OK")
33+
--
34+
2.45.4
35+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
From 7a7d2de96b22a9adf9208afcc9547e1001569fef Mon Sep 17 00:00:00 2001
2+
From: =?UTF-8?q?Alex=20Gr=C3=B6nholm?= <alex.gronholm@nextday.fi>
3+
Date: Thu, 22 Jan 2026 01:41:14 +0200
4+
Subject: [PATCH] Fixed security issue around wheel unpack (#675)
5+
6+
A maliciously crafted wheel could cause the permissions of a file outside the unpack tree to be altered.
7+
8+
Fixes CVE-2026-24049.
9+
Upstream Patch Reference: https://github.com/pypa/wheel/commit/7a7d2de96b22a9adf9208afcc9547e1001569fef.patch
10+
---
11+
wheel/cli/unpack.py | 4 ++--
12+
1 file changed, 2 insertions(+), 2 deletions(-)
13+
14+
diff --git a/wheel/cli/unpack.py b/wheel/cli/unpack.py
15+
index d48840e..83dc742 100644
16+
--- a/wheel/cli/unpack.py
17+
+++ b/wheel/cli/unpack.py
18+
@@ -19,12 +19,12 @@ def unpack(path: str, dest: str = ".") -> None:
19+
destination = Path(dest) / namever
20+
print(f"Unpacking to: {destination}...", end="", flush=True)
21+
for zinfo in wf.filelist:
22+
- wf.extract(zinfo, destination)
23+
+ target_path = Path(wf.extract(zinfo, destination))
24+
25+
# Set permissions to the same values as they were set in the archive
26+
# We have to do this manually due to
27+
# https://github.com/python/cpython/issues/59999
28+
permissions = zinfo.external_attr >> 16 & 0o777
29+
- destination.joinpath(zinfo.filename).chmod(permissions)
30+
+ target_path.chmod(permissions)
31+
32+
print("OK")
33+
--
34+
2.45.4
35+

SPECS/python-virtualenv/python-virtualenv.spec

Lines changed: 46 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.26.6
4-
Release: 2%{?dist}
4+
Release: 3%{?dist}
55
License: MIT
66
Vendor: Microsoft Corporation
77
Distribution: Mariner
@@ -13,6 +13,12 @@ Patch1000: CVE-2025-50181v0.patch
1313
Patch1001: CVE-2025-50181v1.patch
1414
Patch1002: CVE-2025-50181v2.patch
1515
Patch1003: CVE-2025-50181v3.patch
16+
Patch1004: CVE-2026-1703v0.patch
17+
Patch1005: CVE-2026-1703v1.patch
18+
Patch1006: CVE-2026-1703v2.patch
19+
Patch1007: CVE-2026-24049v0.patch
20+
Patch1008: CVE-2026-24049v1.patch
21+
Patch1009: CVE-2026-24049v2.patch
1622
BuildArch: noarch
1723

1824
%description
@@ -58,6 +64,8 @@ echo "Manually Patching virtualenv-20.26.6/src/virtualenv/seed/wheels/embed/pip-
5864
mkdir -p unpacked_pip-24.0-py3-none-any
5965
unzip src/virtualenv/seed/wheels/embed/pip-24.0-py3-none-any.whl -d unpacked_pip-24.0-py3-none-any
6066
patch -p1 -d unpacked_pip-24.0-py3-none-any < %{PATCH1000}
67+
echo "Manually Patching virtualenv-20.26.6/src/virtualenv/seed/wheels/embed/pip-24.0-py3-none-any.whl/pip/_internal/utils/unpacking.py"
68+
patch -p1 -d unpacked_pip-24.0-py3-none-any < %{PATCH1004}
6169
# Remove the original file
6270
rm -f src/virtualenv/seed/wheels/embed/pip-24.0-py3-none-any.whl
6371
# After patching, re-zip the contents back into a .whl
@@ -70,6 +78,8 @@ echo "Manually Patching virtualenv-20.26.6/src/virtualenv/seed/wheels/embed/pip-
7078
mkdir -p unpacked_pip-24.2-py3-none-any
7179
unzip src/virtualenv/seed/wheels/embed/pip-24.2-py3-none-any.whl -d unpacked_pip-24.2-py3-none-any
7280
patch -p1 -d unpacked_pip-24.2-py3-none-any < %{PATCH1001}
81+
echo "Manually Patching virtualenv-20.26.6/src/virtualenv/seed/wheels/embed/pip-24.2-py3-none-any.whl/pip/_internal/utils/unpacking.py"
82+
patch -p1 -d unpacked_pip-24.2-py3-none-any < %{PATCH1005}
7383
# Remove the original file
7484
rm -f src/virtualenv/seed/wheels/embed/pip-24.2-py3-none-any.whl
7585
# After patching, re-zip the contents back into a .whl
@@ -102,6 +112,8 @@ echo "Manually Patching virtualenv-16.7.9-py2.py3-none-any/virtualenv_support/pi
102112
mkdir -p unpacked_pip-19.3.1-py2.py3-none-any
103113
unzip unpacked_virtualenv-16.7.9-py2.py3-none-any/virtualenv_support/pip-19.3.1-py2.py3-none-any.whl -d unpacked_pip-19.3.1-py2.py3-none-any
104114
patch -p1 -d unpacked_pip-19.3.1-py2.py3-none-any < %{PATCH1003}
115+
echo "Manually Patching virtualenv-16.7.9-py2.py3-none-any/virtualenv_support/pip-19.3.1-py2.py3-none-any.whl/pip/_internal/utils/unpacking.py"
116+
patch -p1 -d unpacked_pip-19.3.1-py2.py3-none-any < %{PATCH1006}
105117
# Repack the inner wheel
106118
rm -f unpacked_virtualenv-16.7.9-py2.py3-none-any/virtualenv_support/pip-19.3.1-py2.py3-none-any.whl
107119
pushd unpacked_pip-19.3.1-py2.py3-none-any
@@ -115,6 +127,36 @@ pushd unpacked_virtualenv-16.7.9-py2.py3-none-any
115127
zip -r ../tests/unit/create/unpacked_virtualenv-16.7.9-py2.py3-none-any *
116128
popd
117129

130+
echo "Manually Patching virtualenv-20.26.6/src/virtualenv/seed/wheels/embed/setuptools-75.1.0-py3-none-any.whl/setuptools/_vendor/wheel/cli/unpack.py"
131+
mkdir -p unpacked_setuptools-75.1.0-py3-none-any
132+
unzip src/virtualenv/seed/wheels/embed/setuptools-75.1.0-py3-none-any.whl -d unpacked_setuptools-75.1.0-py3-none-any
133+
patch -p1 -d unpacked_setuptools-75.1.0-py3-none-any < %{PATCH1007}
134+
rm -f src/virtualenv/seed/wheels/embed/setuptools-75.1.0-py3-none-any.whl
135+
pushd unpacked_setuptools-75.1.0-py3-none-any
136+
zip -r ../src/virtualenv/seed/wheels/embed/setuptools-75.1.0-py3-none-any.whl *
137+
popd
138+
rm -rf unpacked_setuptools-75.1.0-py3-none-any
139+
140+
echo "Manually Patching virtualenv-20.26.6/src/virtualenv/seed/wheels/embed/wheel-0.42.0-py3-none-any.whl/wheel/cli/unpack.py"
141+
mkdir -p unpacked_wheel-0.42.0-py3-none-any
142+
unzip src/virtualenv/seed/wheels/embed/wheel-0.42.0-py3-none-any.whl -d unpacked_wheel-0.42.0-py3-none-any
143+
patch -p1 -d unpacked_wheel-0.42.0-py3-none-any < %{PATCH1008}
144+
rm -f src/virtualenv/seed/wheels/embed/wheel-0.42.0-py3-none-any.whl
145+
pushd unpacked_wheel-0.42.0-py3-none-any
146+
zip -r ../src/virtualenv/seed/wheels/embed/wheel-0.42.0-py3-none-any.whl *
147+
popd
148+
rm -rf unpacked_wheel-0.42.0-py3-none-any
149+
150+
echo "Manually Patching virtualenv-20.26.6/src/virtualenv/seed/wheels/embed/wheel-0.44.0-py3-none-any.whl/wheel/cli/unpack.py"
151+
mkdir -p unpacked_wheel-0.44.0-py3-none-any
152+
unzip src/virtualenv/seed/wheels/embed/wheel-0.44.0-py3-none-any.whl -d unpacked_wheel-0.44.0-py3-none-any
153+
patch -p1 -d unpacked_wheel-0.44.0-py3-none-any < %{PATCH1009}
154+
rm -f src/virtualenv/seed/wheels/embed/wheel-0.44.0-py3-none-any.whl
155+
pushd unpacked_wheel-0.44.0-py3-none-any
156+
zip -r ../src/virtualenv/seed/wheels/embed/wheel-0.44.0-py3-none-any.whl *
157+
popd
158+
rm -rf unpacked_wheel-0.44.0-py3-none-any
159+
118160
%generate_buildrequires
119161

120162
%build
@@ -136,6 +178,9 @@ tox -e py
136178
%{_bindir}/virtualenv
137179

138180
%changelog
181+
* Tue Feb 24 2026 BinduSri Adabala <v-badabala@microsoft.com> - 20.26.6-3
182+
- Patch for CVE-2026-1703 & CVE-2026-24049
183+
139184
* Wed Jul 09 2025 Aninda Pradhan <v-anipradhan@microsoft.com> - 20.26.6-2
140185
- Add patch to fix CVE-2025-50181 in urllib3 poolmanager.py
141186

0 commit comments

Comments
 (0)