From f645154c5a752ede092e77c6bc88f6695788fd4c Mon Sep 17 00:00:00 2001 From: PengLAI Code Date: Sat, 29 Aug 2026 14:15:27 +0800 Subject: [PATCH] [CVE] [Upstream] add patch to fix CVE-2026-3219 to #IK222U unpack_file() ran all zip format checks before any tar check, so a crafted .tar.gz with a trailing zip end-of-central-directory record was handed to the zip unpacker. Detection is now ordered content_type, filename extension, then magic signature, and the signature is only trusted when exactly one of is_zipfile/is_tarfile matches. Registered as Patch1004 with release 11 because this branch does not carry the CVE-2026-13346 fix that occupies those slots on a23. Upstream: https://github.com/pypa/pip/pull/13870 project: TC2024080204 Assisted-by: PengLAI Code --- CVE-2026-3219.patch | 96 +++++++++++++++++++++++++++++++++++++++++++++ python-pip.spec | 11 +++++- 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 CVE-2026-3219.patch diff --git a/CVE-2026-3219.patch b/CVE-2026-3219.patch new file mode 100644 index 0000000..1bedf18 --- /dev/null +++ b/CVE-2026-3219.patch @@ -0,0 +1,96 @@ +From: Damian Shaw +Date: Fri, 17 Apr 2026 23:12:10 -0400 +Subject: [PATCH] add patch to fix CVE-2026-3219 + +unpack_file() decided the archive format by evaluating every zip check +first (content-type, filename extension and zipfile.is_zipfile) before +any tar check. zipfile.is_zipfile only scans for an end-of-central- +directory record, so a crafted .tar.gz carrying a trailing EOCD record +satisfies both is_zipfile and is_tarfile and gets handed to the zip +unpacker, so the archive is processed by the wrong extractor. + +Order the detection by decreasing reliability instead: explicit +content_type, then filename extension, then the magic signature check, +and only trust the signature when exactly one of is_zipfile/is_tarfile +matches. Files matching both are refused. + +Squashed backport of upstream https://github.com/pypa/pip/pull/13870 +(commits 9b08c2b..b6e2826), adapted to 23.3.1 which uses Optional[str] +rather than PEP 604 unions. + +Adapted-by: PengLAI Code +--- + src/pip/_internal/utils/unpacking.py | 63 ++++++++++++++++++++++++++++++---------------------- + 1 file changed, 41 insertions(+), 22 deletions(-) + +diff --git a/src/pip/_internal/utils/unpacking.py b/src/pip/_internal/utils/unpacking.py +--- a/src/pip/_internal/utils/unpacking.py ++++ b/src/pip/_internal/utils/unpacking.py +@@ -245,26 +245,45 @@ + content_type: Optional[str] = None, + ) -> None: ++ """Unpack ``filename`` into ``location``. ++ ++ Archive format is chosen in order of decreasing reliability: ++ ``content_type``, then filename extension, then magic signature ++ (unambiguous matches only). ++ """ + filename = os.path.realpath(filename) +- if ( +- content_type == "application/zip" +- or filename.lower().endswith(ZIP_EXTENSIONS) +- or zipfile.is_zipfile(filename) +- ): +- unzip_file(filename, location, flatten=not filename.endswith(".whl")) +- elif ( +- content_type == "application/x-gzip" +- or tarfile.is_tarfile(filename) +- or filename.lower().endswith(TAR_EXTENSIONS + BZ2_EXTENSIONS + XZ_EXTENSIONS) +- ): ++ zip_flatten = not filename.endswith(".whl") ++ ++ def _unzip() -> None: ++ unzip_file(filename, location, flatten=zip_flatten) ++ ++ def _untar() -> None: + untar_file(filename, location) +- else: +- # FIXME: handle? +- # FIXME: magic signatures? +- logger.critical( +- "Cannot unpack file %s (downloaded from %s, content-type: %s); " +- "cannot detect archive format", +- filename, +- location, +- content_type, +- ) +- raise InstallationError(f"Cannot determine archive format of {location}") ++ ++ if content_type == "application/zip": ++ return _unzip() ++ if content_type == "application/x-gzip": ++ return _untar() ++ ++ if filename.lower().endswith(ZIP_EXTENSIONS): ++ return _unzip() ++ if filename.lower().endswith(TAR_EXTENSIONS + BZ2_EXTENSIONS + XZ_EXTENSIONS): ++ return _untar() ++ ++ # avoid ambiguous case where both signature checks return True ++ is_zipfile = zipfile.is_zipfile(filename) ++ is_tarfile = tarfile.is_tarfile(filename) ++ if is_zipfile and not is_tarfile: ++ return _unzip() ++ if is_tarfile and not is_zipfile: ++ return _untar() ++ if is_zipfile and is_tarfile: ++ logger.error("Ambiguous file signature in %s.", filename) ++ ++ logger.critical( ++ "Cannot unpack file %s (downloaded from %s, content-type: %s); " ++ "cannot detect archive format", ++ filename, ++ location, ++ content_type, ++ ) ++ raise InstallationError(f"Cannot determine archive format of {location}") diff --git a/python-pip.spec b/python-pip.spec index 3e09ef2..41372bc 100644 --- a/python-pip.spec +++ b/python-pip.spec @@ -1,4 +1,4 @@ -%define anolis_release 10 +%define anolis_release 11 %bcond_with tests %bcond_with doc @@ -49,6 +49,10 @@ Patch0011: 0012-add-patch-to-fix-CVE-2026-21441.patch Patch001002: 001002-bugfix-for-CVE-2026-8643.patch Patch1003: 0001-Fix-TypeError-when-reading-HTTPResponse-with-amt-Non.patch +# CVE-2026-3219 +# Source: upstream +# Reference: https://github.com/pypa/pip/pull/13870 +Patch1004: CVE-2026-3219.patch %global bundled() %{expand: Provides: bundled(python%{1}dist(cachecontrol)) = 0.13.1 @@ -252,6 +256,11 @@ pytest_k='not completion' %endif %changelog +* Sat Aug 29 2026 PengLAI Code - 23.3.1-11 +- Fix CVE-2026-3219 +- Upstream patch: https://github.com/pypa/pip/pull/13870 +- Adapted by PengLAI Code + * Thu Jul 09 2026 YeXingchen - 23.3.1-10 - Fix TypeError when reading HTTPResponse with amt=None -- Gitee