Skip to content

3.7.17.8: eMudhra distrust, upstream security fixes, expat 2.9.0, pip 24.0 / setuptools 68 - #117

Merged
icanhasmath merged 129 commits into
3.7.17.xfrom
3.7.17.8-security
Oct 29, 2026
Merged

icanhasmath merged 129 commits into
3.7.17.xfrom
3.7.17.8-security

Conversation

@icanhasmath

@icanhasmath icanhasmath commented Oct 29, 2026 •

Copy link
Copy Markdown

Security release 3.7.17.8 for the 3.7 line (base 3.7.17.x = tag v3.7.17.7). It brings 3.7 to the same footing as 3.9.25.x: the eMudhra SPKI denylist, the upstream security fixes since 3.7 went EOL, libexpat 2.9.0, and a refreshed ensurepip.

What's in it

Each commit that needed a 3.7 adaptation says so in a 3.7.17.x: paragraph. The adaptations cover syntax and APIs newer than 3.7: f-string =, parenthesized with, removesuffix, sys.audit/io.open_code, test.support helpers, and the http: fast path in urlsplit. The full list of changes is in Doc/whatsnew/3.7.rst.

Not included

Testing

Linux (x86_64, OpenSSL 1.1.1w, -j8 -w), compared with a 3.7.17.7 build on the same machine:

  • 382 tests OK, against 379 on the baseline.
  • Final failures: test_email (test_variable_tzname, also on base), test_socket (VSOCK, also on base) and test_concurrent_futures (test_timeout, which fails on base too when run serially).
  • No test case fails only on the new build.
  • Four modules that fail on 3.7.17.7 now pass: test_ipaddress, test_tempfile, test_xml_etree and test_xml_etree_c.

Windows x64 (EC2 test box, VS 2022 v143), compared with a 3.7.17.7 build made the same way:

  • Libraries: ActiveState shared/zlib 1.3.2, shared/xz-utils 5.8.4 and OpenSSL 1.1.1w. python37.dll imports z.dll and _lzma imports liblzma.dll.
  • Coverage: 46 test modules covering everything this PR touches.
  • No case fails only on the new build.
  • Fixed relative to base: the two tarfile symlink-escape cases, the XMLPullParser cases, testPrivateNetworks and one venv case.
  • Same on both builds: the test_venv failures, from running inside a build tree.
  • ICF probe: subclass + x raises TypeError.

After the first review (pythongh-137836, pythongh-120298/pythongh-120384, pythongh-134062, the bpo-9949 test follow-ups, pyexpatns.h and docs). The full-suite runs above predate these commits; these modules were rerun:

  • Linux: 19 modules pass, including test_list, test_userlist, test_htmlparser, test_ipaddress, test_pyexpat, the etree, sax and minidom tests, test_os, test_shutil, test_unittest, test_ntpath, test_tarfile, test_tempfile and test_multiprocessing_forkserver.
    • pyexpat's exported symbols are now PyExpat_XML_SetHashSalt16Bytes and PyExpat_XML_SetAllocTracker*.
  • The three fixes, checked on both builds:
    • On 3.7.17.7, IPv4Network("192.168.1.255/32") and IPv4Network("192.168.1.0/24") hash equal, <plaintext> content is parsed as tags, and lst[::-1] = <iterator that clears lst> segfaults.
    • On this branch, the hashes differ, the <plaintext> content is data, and the assignment raises ValueError.
  • Windows x64 (rebuilt on the test box): 17 modules pass, including test_shutil and test_unittest. test_move_dangling_symlink and test_detect_module_clash run and pass with symlinks enabled.

ensurepip: a fresh venv gets pip 24.0.post4 (vendored urllib3 1.26.20 fork, requests 2.31.0, certifi 2026.10.23, no RequestsDependencyWarning under -W error) and setuptools 68.0.0.post3, and pip download from PyPI works. test_ensurepip and test_venv pass.

Before merge

  • Nothing else is pending: pip 24.0.post4 and setuptools 68.0.0.post3 are released and bundled.
  • No GitHub CI build or tests: the build and test workflows only run on PRs into master, 3.8 and 3.7, so they don't run here. The testing above is the verification.
  • Verify bundled pip and setuptools fails, and that's expected. It runs on any PR that touches Lib/ensurepip/_bundled/. Tools/scripts/verify_ensurepip_wheels.py looks up each bundled wheel's version on PyPI, and the ActiveState releases 24.0.post4 and 68.0.0.post3 aren't there, so it stops with KeyError: '24.0.post4' before it compares any checksum. 3.9.25.1: all upstream security fixes since 3.9.25 + eMudhra ssl distrust, ensurepip pip 26.0.1.post1 #88 (3.9.25.1, which bundles ActiveState pip 26.0.1.post1) fails the same way. The bundled wheels are byte-identical to the GitHub release assets: pip 749401b66b9dee893c560b12b8ee3b6f2d2d3600bdc047350c1a9d6db9047c17, setuptools 95bb21258fbcb75b5d7d3740ce296991641e8c78a0de9590747ba2d11aa81c43.

miss-islington and others added 30 commits October 29, 2026 10:13
…ythonGH-25099) (pythonGH-25815)

Reverts commit e653d4d and makes
parsing even more strict. Like socket.inet_pton() any leading zero
is now treated as invalid input.

Signed-off-by: Christian Heimes <christian@python.org>

Co-authored-by: Łukasz Langa <lukasz@langa.pl>
(cherry picked from commit 60ce8f0)
(cherry picked from commit 5374fbc)

3.7.17.x: 3.7 still had the octal/decimal ambiguity check that 3.8
removed (e653d4d); it is now unreachable, so it and its test are
dropped.
…ssing (pythonGH-98501) (python#98504)

Linux abstract sockets are insecure as they lack any form of filesystem
permissions so their use allows anyone on the system to inject code into
the process.

This removes the default preference for abstract sockets in
multiprocessing introduced in Python 3.9+ via
python#18866 while fixing
python#84031.

Explicit use of an abstract socket by a user now generates a
RuntimeWarning.  If we choose to keep this warning, it should be
backported to the 3.7 and 3.8 branches.
(cherry picked from commit 49f6106)

Co-authored-by: Gregory P. Smith <greg@krypto.org>
(cherry picked from commit b43496c)
…ythonGH-107846) (python#108274)

(cherry picked from commit acbd3f9)

Co-authored-by: Petr Viktorin <encukou@gmail.com>
Co-authored-by: Victor Stinner <vstinner@python.org>
Co-authored-by: Lumír 'Frenzy' Balhar <frenzy.madness@gmail.com>
(cherry picked from commit 42deeab)
…04 codecs read out of bounds (pythongh-111695) (pythongh-111780)

(cherry picked from commit c8faa35)

Co-authored-by: Masayuki Moriyama <masayuki.moriyama@miraclelinux.com>
(cherry picked from commit 08b640e)
… cleanup (pythonGH-99930) (pythonGH-112842)

(cherry picked from commit 81c16cd)

Co-authored-by: Søren Løvborg <sorenl@unity3d.com>
(cherry picked from commit d54e22a)

3.7.17.x: the TemporaryDirectory test_modes/test_flags tests come along
(3.7 already had the chmod/chflags cleanup they cover); test imports
stat and uses test.support.skip_unless_symlink.
…ythonGH-110016) (pythonGH-113915)

Raise BadZipFile when try to read an entry that overlaps with other entry or
central directory.
(cherry picked from commit 66363b9)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
(cherry picked from commit a2c5999)

3.7.17.x: ZipInfo.__init__ only gains _end_offset (3.7 never initialized
compress_size/file_size there); tests use the 3.7 requires_zlib
decorator; the unrelated bz2 test in the hunk is dropped.
…onGH-114146)

(cherry picked from commit 74208ed)

Co-authored-by: Łukasz Langa <lukasz@langa.pl>
(cherry picked from commit 8fc8c45)

3.7.17.x: 3.7 has no io.open_code(), so .pth files are still opened with
open().
…-118488) (pythonGH-118741)

Co-authored-by: Łukasz Langa <lukasz@langa.pl>
(cherry picked from commit 5130731)

3.7.17.x: hand-merged into 3.7's os_mkdir_impl (no PySys_Audit or
mkdirat probing in 3.7); the test uses slicing instead of
str.removeprefix().
…ketpair()` fallback (pythonGH-122134) (python#122428)

Authenticate socket connection for `socket.socketpair()` fallback when the platform does not have a native `socketpair` C API.  We authenticate in-process using `getsocketname` and `getpeername` (thanks to Nathaniel J Smith for that suggestion).

(cherry picked from commit 78df104)

Co-authored-by: Seth Michael Larson <seth@python.org>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
(cherry picked from commit 06fa244)

3.7.17.x: tests use test.support.IPV6_ENABLED (no
test.support.socket_helper in 3.7).
…se of importlib.reload. (pythonGH-122493) (pythonGH-122508)

(cherry picked from commit f071f01)

Co-authored-by: Russell Keith-Magee <russell@keith-magee.com>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
(cherry picked from commit 3f5d9d1)
… are sound (pythonGH-122233) (python#122610)

Per RFC 2047:

> [...] these encoding schemes allow the
> encoding of arbitrary octet values, mail readers that implement this
> decoding should also ensure that display of the decoded data on the
> recipient's terminal will not cause unwanted side-effects

It seems that the "quoted-word" scheme is a valid way to include
a newline character in a header value, just like we already allow
undecodable bytes or control characters.
They do need to be properly quoted when serialized to text, though.

This should fail for custom fold() implementations that aren't careful
about newlines.

(cherry picked from commit 0976339)

Co-authored-by: Petr Viktorin <encukou@gmail.com>
Co-authored-by: Bas Bloemsaat <bas@bloemsaat.org>
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
(cherry picked from commit f7be505)

3.7.17.x: str.removesuffix() (3.9+) replaced by slicing in
email.generator.
…nd by urlsplit are of IPv6 or IPvFuture format (python#103849) (python#126976)

Co-authored-by: Gregory P. Smith <greg@krypto.org>
(cherry picked from commit 29f348e)

Co-authored-by: JohnJamesUtley <81572567+JohnJamesUtley@users.noreply.github.com>
(cherry picked from commit ddca295)

3.7.17.x: 3.7's urlsplit() still has a separate http: fast path, which
gets the same check; IPv6 scope ids ("%zone") are validated here because
3.7's ipaddress cannot parse them (support came in 3.9).
…stent with IPv4 (pythonGH-122793) (pythonGH-123819) (pythonGH-127571)

Make IPv4-mapped IPv6 address properties consistent with IPv4.
(cherry picked from commit 76a1c5d)
(cherry picked from commit b58da40)

Co-authored-by: Seth Michael Larson <seth@python.org>
(cherry picked from commit a897b4a)
…ythonGH-119514) (python#130248)

The IMAP4 client could consume an arbitrary amount of memory when trying
to connect to a malicious server, because it read a "literal" data with a
single read(size) call, and BufferedReader.read() allocates the bytes
object of the specified size before reading. Now the IMAP4 client reads data
by chunks, therefore the amount of used memory is limited by the
amount of the data actually been sent by the server.
(cherry picked from commit 735f25c)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
(cherry picked from commit f116a9c)
…in names for parsed URLs (pythonGH-129418) (python#129530)

(cherry picked from commit d89a5f6)

Co-authored-by: Seth Michael Larson <seth@python.org>
Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
(cherry picked from commit ff4e5c2)

3.7.17.x: the http: fast path calls _check_bracketed_netloc() too.
…ncoded-word (pythonGH-122754) (pythonGH-131412)

Email generators using email.policy.default may convert an RFC 2047
encoded-word to unencoded form during header refolding. In a structured
header, this could allow 'specials' chars outside a quoted-string,
leading to invalid address headers and enabling spoofing. This change
ensures a parsed encoded-word that contains specials is kept as an
encoded-word while the header is refolded.

[Better fix from @bitdancer.]

(cherry picked from commit 295b53d)

Co-authored-by: Mike Edmunds <medmunds@gmail.com>
Co-authored-by: R David Murray <rdmurray@bitdance.com>
(cherry picked from commit 9a31386)
…ed-string (pythonGH-122753) (pythonGH-129111) (pythonGH-132371)

Email generators using email.policy.default could incorrectly omit the
quote ('"') characters from a quoted-string during header refolding,
leading to invalid address headers and enabling header spoofing. This
change restores the quote characters on a bare-quoted-string as the
header is refolded, and escapes backslash and quote chars in the string.

(cherry picked from commit 5aaf416)
(cherry picked from commit a4ef689)

Co-authored-by: R. David Murray <rdmurray@bitdance.com>
Co-authored-by: Mike Edmunds <medmunds@gmail.com>
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
(cherry picked from commit d4df3c5)
…er with an error handler (pythonGH-129648) (pythonGH-133944) (python#134346)

* [3.9] pythongh-133767: Fix use-after-free in the unicode-escape decoder with an error handler (pythonGH-129648) (pythonGH-133944)

If the error handler is used, a new bytes object is created to set as
the object attribute of UnicodeDecodeError, and that bytes object then
replaces the original data. A pointer to the decoded data will became invalid
after destroying that temporary bytes object. So we need other way to return
the first invalid escape from _PyUnicode_DecodeUnicodeEscapeInternal().

_PyBytes_DecodeEscape() does not have such issue, because it does not
use the error handlers registry, but it should be changed for compatibility
with _PyUnicode_DecodeUnicodeEscapeInternal().
(cherry picked from commit 9f69a58)
(cherry picked from commit 6279eb8)
(cherry picked from commit a75953b)
(cherry picked from commit 0c33e5b)
(cherry picked from commit 8b528ca)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>

3.7.17.x: hand-ported. 3.7 names the helper _PyUnicode_DecodeUnicodeEscape
(no consumed argument); the char-returning variant is
_PyUnicode_DecodeUnicodeEscape2 and the old symbol stays as a wrapper.
Python/ast.c is unchanged: it passes errors=NULL, so no error handler can
replace the input buffer. The _PyBytes_DecodeEscape change is not ported;
upstream made it only for API symmetry (the bytes decoder never calls the
error handler registry).
(cherry picked from commit 8d35fd1)
The CVE-2024-4032 backport (89f48de) added 0.0.0.0/8 and
255.255.255.255/32 to the private ranges but kept the old assertion that
0.0.0.0/0 is not private. Upstream changed that assertion to True in the
same fix (pythonGH-113179); 3.9 and later expect True too. Test-only.
…ing (pythonGH-128841) (pythonGH-134615)

Limit length of IP address string to 39

(cherry picked from commit 47f1161)

Co-authored-by: Seth Michael Larson <seth@python.org>
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
(cherry picked from commit 78394a6)

3.7.17.x: scope-id test cases dropped (3.7's ipaddress has no scope
ids).
…IPv4 address (pythonGH-134836) (pythonGH-135090)

(cherry picked from commit d83576b)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
(cherry picked from commit 24eaf53)

3.7.17.x: scope-id test cases dropped (3.7's ipaddress has no scope
ids).

3.7.17.x: the ::ffff:255.255.255.255 case expects 3.7's hex form
::ffff:ffff:ffff, because pythongh-87799 (dotted IPv4-mapped output) is not
backported.
…h.realpath(strict='allow_missing')` (pythonGH-135037) (pythonGH-135084)

Addresses CVEs 2024-12718, 2025-4138, 2025-4330, and 2025-4517.
(cherry picked from commit 3612d8f)

Co-authored-by: Łukasz Langa <lukasz@langa.pl>
Co-authored-by: Petr Viktorin <encukou@gmail.com>
Co-authored-by: Seth Michael Larson <seth@python.org>
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>

3.7.17.x: hand-ported (the 3.9 commit relies on the strict parameter of
os.path.realpath, which 3.9 got from bpo-43757 / pythonGH-135035).
- posixpath.realpath gains strict=False|True|ALLOW_MISSING (3.9.25 code).
- ntpath.realpath() gains the strict keyword here; it only starts
  resolving links on Windows in the later bpo-9949 commit.
- pathlib is left alone (bpo-43757's pathlib change is not needed here).
- Tests: test_tarfile changes taken; 3.10+ syntax (parenthesized with,
  f'{x=}', BaseException.add_note) rewritten for 3.7.
(cherry picked from commit dd8f187)

3.7.17.x: test_posixpath gains the realpath strict/ALLOW_MISSING tests
from bpo-43757 and pythongh-135034.
Restore fix from 011525e.
(cherry picked from commit 4fedd71)

Co-authored-by: Julien Palard <julien@palard.fr>
(cherry picked from commit 9d2c2a8)
… input in HTMLParser (pythonGH-135464) (pythonGH-135486)

End-of-file errors are now handled according to the HTML5 specs --
comments and declarations are automatically closed, tags are ignored.
(cherry picked from commit 6eb6c5d)
(cherry picked from commit 8d1b3df)

3.7.17.x: 3.7 keeps the deprecated HTMLParser.unescape() method and its
test.
… the HTML5 standard (pythonGH-135664) (pythonGH-136276)

* "--!>" now ends the comment.
* "-- >" no longer ends the comment.
* Support abnormally ended empty comments "<-->" and "<--->".

---------
(cherry picked from commit 8ac7613)

Co-author: Kerim Kabirov <the.privat33r+gh@pm.me>

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Ezio Melotti <ezio.melotti@gmail.com>
(cherry picked from commit a63f229)
…ccording to the HTML5 standard (pythonGH-135930) (pythonGH-136268) (python#136293)

* Whitespaces no longer accepted between `</` and the tag name.
  E.g. `</ script>` does not end the script section.

* Vertical tabulation (`\v`) and non-ASCII whitespaces no longer recognized
  as whitespaces. The only whitespaces are `\t\n\r\f `.

* Null character (U+0000) no longer ends the tag name.

* Attributes and slashes after the tag name in end tags are now ignored,
  instead of terminating after the first `>` in quoted attribute value.
  E.g. `</script/foo=">"/>`.

* Multiple slashes and whitespaces between the last attribute and closing `>`
  are now ignored in both start and end tags. E.g. `<a foo=bar/ //>`.

* Multiple `=` between attribute name and value are no longer collapsed.
  E.g. `<a foo==bar>` produces attribute "foo" with value "=bar".

* Whitespaces between the `=` separator and attribute name or value are no
  longer ignored. E.g. `<a foo =bar>` produces two attributes "foo" and
  "=bar", both with value None; `<a foo= bar>` produces two attributes:
  "foo" with value "" and "bar" with value None.

* Fix data loss after unclosed script or style tag (pythongh-86155).

Also backport test.support.subTests() (pythongh-135120).

---------
(cherry picked from commit 0243f97)
(cherry picked from commit c555f88)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Ezio Melotti <ezio.melotti@gmail.com>
Co-authored-by: Waylan Limberg <waylan.limberg@icloud.com>
(cherry picked from commit 6c97200)

3.7.17.x: Lib/html/parser.py taken from 3.9 plus 3.7's deprecated
unescape() method; test.support.subTests() is added without positional-
only parameters (3.8+ syntax).
… the "=" separator in HTMLParser (pythonGH-136908) (pythonGH-136922)

This fixes a regression introduced in pythonGH-135930.
(cherry picked from commit dee6501)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
(cherry picked from commit 06fc882)
…r offsets are non-negative (pythonGH-137027) (pythonGH-137645)

pythongh-130577: tarfile now validates archives to ensure member offsets are non-negative (pythonGH-137027)

(cherry picked from commit 7040aa5)

Co-authored-by: Alexander Urieles <aeurielesn@users.noreply.github.com>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
(cherry picked from commit 73f03e4)
… in HTMLParser (pythonGH-135310) (pythonGH-137784)

(cherry picked from commit 4d02f31)

Co-authored-by: Timon Viola <44016238+timonviola@users.noreply.github.com>
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
(cherry picked from commit 4dea0fb)
…bparsers in `pyexpat` (pythonGH-139403) (pythonGH-139614)

Within libexpat, a parser created via `XML_ExternalEntityParserCreate`
is relying on its parent parser throughout its entire lifetime.
Prior to this fix, is was possible for the parent parser to be
garbage-collected too early.

(cherry picked from commit 6edb2dd)
(cherry picked from commit 598165e)

3.7.17.x: only the parser lifetime tests; the reparse deferral tests
come with pythongh-115398.
icanhasmath and others added 8 commits October 29, 2026 11:46
The 2.7-branch Unicode refactor for CVE-2023-27043 (c98f6b9) does not
port to Python 3: its code change uses the Python-2-only `unicode` name
and UTF-8-encodes to bytes, both of which are no-ops / errors on 3.x
where `str` is already Unicode. Port only the test intent.

Verified against the current 3.7.17.x parseaddr: strict mode accepts
ASCII and non-ASCII input and agrees with non-strict mode, so no source
change to Lib/email/utils.py is required.

(cherry picked from commit 99ee836)
The bundled setuptools 47.1.0 is affected by CVE-2022-40897 (ReDoS in
package_index), CVE-2024-6345 (command injection via package URL) and
CVE-2025-47273 (path traversal in PackageIndex.download). Upstream fixed
them in 65.5.1, 70.0.0 and 78.1.1, which require Python >= 3.8, so 3.7
takes the ActiveState security release of setuptools 68.0.0, the last
line that supports 3.7:
https://github.com/ActiveState/setuptools/releases/tag/v68.0.0.2

That release has no wheel asset; this wheel was built from the v68.0.0.2
tag (b70102d) with setup.py bdist_wheel under python:3.7-slim. Against
PyPI's setuptools 68.0.0 wheel, the only content changes are the CVE fixes
(setuptools/package_index.py) and the fork's
setuptools/_distutils/command/build.py change; the dist-info has no
top_level.txt. sha256
14a7da783a9211f5b07717aa0940f34ee7dd5ff400ca54acf2974b33fbe9bec4.

Not fixed in 68.0.0.2: CVE-2026-59890 (GHSA-h35f-9h28-mq5c, MANIFEST.in
exclusion bypass in sdist, fixed upstream in 83.0.0) and
GHSA-xmj3-9gf7-h52w (low, Windows legacy wheel-as-egg install, fixed
upstream in 84.1.0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pip 23.0.1 vendors certifi 2022.12.07, which still trusts the emSign roots
of the compromised eMudhra/emSign CA, and is affected by CVE-2023-5752 and
later pip CVEs. pip 24.0 is the last pip that supports Python 3.7, so 3.7
takes the ActiveState security release of it:
https://github.com/ActiveState/pip/releases/tag/24.0.post3

Its vendored certifi 2026.10.23 keeps emSign Root CA - G1 as the only
emSign root, and the 24.0 line carries backports of CVE-2025-8869,
CVE-2026-1703, CVE-2026-3219, CVE-2026-6357, CVE-2026-8643 and
CVE-2026-13346. The wheel is the release asset, sha256
2cda945c314810ab760bd913874e11c13faca17e64544320fccd90bf7532587f.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pythoncore.vcxproj linked a hard-coded zlib.lib from $(zlibLibDir). The
ActiveState shared/zlib ingredient installs its Windows import library
as z.lib from 1.3.2 on (earlier builds shipped zlib.lib), so the core
would no longer link against the current zlib. The library name is now
the zlibLibName property: z.lib when $(zlibLibDir) has one, zlib.lib
otherwise, and it can be overridden on the msbuild command line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On Windows, 3.7's pathlib.Path.glob('**/*') raises WinError 123
(ERROR_INVALID_NAME) on the test archive's symlinks (pythongh-79487, fixed in
3.8). Now that the extraction filters normalize link targets and links
replace existing files (bpo-12800), those symlinks are created on a
Windows box that allows symlinks, and check_files_present() hit the bug.
Skip the same way TestExtractionFilters.check_context() already does.
Test-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tarfile data and tar filters (pythongh-102950, pythongh-135034 and the later
link fixes) decide whether a member escapes the destination by calling
os.path.realpath(). On Windows, 3.7's ntpath.realpath() was abspath():
it never resolved symbolic links or junctions, so the filters accepted
symlinks that point outside the destination. On a Windows box that may
create symlinks, test_tarfile's test_absolute_symlink and
test_parent_symlink2 fail on 3.7.17.7 for this reason.

This takes ntpath.realpath() from the ActiveState 3.9.25.x line, which
is upstream's 3.8 implementation (bpo-9949, pythonGH-15287) plus the strict
parameter and os.path.ALLOW_MISSING (bpo-43757, pythongh-135034). It uses
nt._getfinalpathname() and nt.readlink(), which 3.7 has. 3.7's versions
of both only take str, so bytes paths are resolved through
os.fsdecode()/os.fsencode().

This is a behavior change on Windows, matching 3.8 and later:
os.path.realpath() now returns the target of symbolic links and
junctions instead of the unresolved absolute path.

test_ntpath gains the realpath tests from 3.9.25.x. 3.7's ntpath still
defines an XP fallback _getfinalpathname() on non-Windows platforms, so
the tests check the nt module for the real one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.7.17.8 is an ActiveState security release of the 3.7 line: the eMudhra
SPKI denylist (CVE-2026-115557), the upstream security fixes released for
3.8 through 3.11 since 3.7.17 that apply to 3.7 (ported from the
ActiveState 3.9.25.x line), libexpat 2.9.0, ensurepip pip 24.0.post3 and
setuptools 68.0.0.2, and the Windows /OPT:REF,NOICF link fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pip 24.0.post3 still vendored urllib3 1.26.17 and an unpatched requests
2.31.0. ActiveState pip 24.0.post4 (ActiveState/pip#16) vendors
ActiveState urllib3 1.26.20.post4 (CVE-2023-45803, CVE-2024-37891,
CVE-2025-50181, CVE-2025-66418, CVE-2025-66471, CVE-2026-21441,
CVE-2026-44431, CVE-2026-97687, CVE-2026-97689) and backports the
requests fixes for CVE-2024-47081 and CVE-2026-25645. certifi stays at
2026.10.23. The wheel is the release asset, sha256
749401b66b9dee893c560b12b8ee3b6f2d2d3600bdc047350c1a9d6db9047c17.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
setuptools 68.0.0.2 still had CVE-2026-59890 (GHSA-h35f-9h28-mq5c,
MANIFEST.in exclusion bypass in sdist) and GHSA-xmj3-9gf7-h52w (path
escape via namespace_packages.txt during legacy wheel installation).
ActiveState setuptools 68.0.0.post3 (ActiveState/setuptools#7, #8) fixes
both. The wheel is the release asset, sha256
95bb21258fbcb75b5d7d3740ce296991641e8c78a0de9590747ba2d11aa81c43.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@ezequielp-activestate ezequielp-activestate left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes for three security fixes that the 3.9.25.x line carries but this PR leaves out, and doesn't list under "Not included". Everything else checks out; details below.

🔴 Missing fixes (on 3.9.25.x, not here)

  1. pythongh-137836 — HTMLParser RAWTEXT/PLAINTEXT elements (3.9.25.x 941811fc9d, listed in 3.9.25's Security NEWS).
  2. pythongh-120298 / pythongh-120384 — list use-after-free in rich compare and out-of-bounds in slice assignment (3.9.25.x 42762bb098).
    • pr117:Objects/listobject.c:2664 still returns PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op) without holding references.
    • list_ass_subscript still calls PySlice_AdjustIndices before PySequence_Fast(value).
  3. pythongh-134062 — IPv4Network/IPv6Network hash collisions (3.9.25.x 03ac445b11).
    • pr117:Lib/ipaddress.py:692 is still hash(int(self.network_address) ^ int(self.netmask)).
    • This is the weakest of the three. Listing it under "Not included" with a reason would also be fine.

What I checked

Provenance

  • About 70 of the 122 commits have the same added and removed lines as the reviewed 3.9.25.x / 3.10.22.x / 2.7 commits, ignoring context lines.
  • I read every adapted commit's diff against its counterpart, and every commit that has no counterpart. The 3.7 adaptations are all correct. Notable ones:
    • pythongh-133767: the unicode-escape use-after-free fix, with a _PyUnicode_DecodeUnicodeEscape compatibility wrapper. The only remaining caller passes errors=NULL.
    • stringprep: Lib/stringprep.py regenerated with 3.7's UCD 11.0.0 is byte-identical to the committed file.
    • BIO_eof: applied onto 3.7's _add_ca_certs.
    • pythongh-146211: CONNECT-tunnel checks hand-merged onto 3.7's per-line send().
    • pythongh-103848: urlsplit's 3.7 http: fast path and zone-id handling.
    • pythongh-157579: the tempfile race fix's private rmtree keywords keep the public onerror signature.
    • bpo-9949: ntpath.realpath is upstream 3.8 with the late-2019 follow-ups folded in.
  • 3.8+ syntax: grepping the added lines finds no 3.8+ syntax or APIs, and all 87 changed Lib/*.py files compile with a real 3.7.17.

expat

  • Modules/expat/* is byte-identical to 3.9.25.x and reports 2.9.0.
  • xcs.c is wired into setup.py, Setup.dist and both Windows projects.
  • XML_POOR_ENTROPY is now defined for pyexpat on Windows; the 3.7 base was missing it there.
  • Reparse deferral, XML_SetHashSalt16Bytes and the content-model recursion fix are correctly adapted.

ssl

  • Modules/_ssl_distrusted_spki.h is byte-identical to 3.9.25.x and upstream.
  • It is included in the verify path and listed in the setup.py depends and the _ssl project and filters.

Bundles

  • _bundled/ holds only pip 24.0.post4 and setuptools 68.0.0.post3. Their sha256 equals the release assets.
  • The tag trees equal the reviewed PR heads (ActiveState/pip#16, ActiveState/setuptools#8).
  • On python:3.7, ensurepip installs both, pip download works, and test_ensurepip passes.

Windows build changes

  • The NOICF line equals the 3.9.25.3 one.
  • zlibLibName falls back to zlib.lib when there's no z.lib.
  • The mkdir(0o700) code includes sddl.h/aclapi.h only under MS_WINDOWS.

Tests, Linux (base 3.7.17.7 vs head, both built from source in python:3.7)

  • Toolchain: that image links OpenSSL 3.0.9, not 1.1.1w.
  • Full regrtest (-j8 -w -u all,-network,…): base 388 OK / 8 failed, head 392 OK / 4 failed.
    • Fixed on head: test_ipaddress, test_xml_etree, test_xml_etree_c, test_tempfile, and two test_ssl cases.
    • Remaining failures: they fail identically on base. They are chown under rootless podman and 3.7-on-OpenSSL-3 TLS issues.
    • Head only: the new test_imaplib SSL test_truncated_large_literal fails with OpenSSL 3's "unexpected eof while reading". The pre-existing test_issue5949 fails on base the same way, and the plain-socket variant passes, so this is the environment.
  • test_tarfile: 520 → 547 OK. Running head's tests against base's tarfile.py, test_getmembers_big_size hangs (the CVE-2026-11972 DoS), and the filter, offset, long-name and symlink tests fail, so the new tests catch the bugs.
  • --with-pydebug: the unicode, codecs, tarfile, zipfile, pyexpat, etree, bz2, lzma, email and httplib tests pass. -R 3:3 on codecs, pyexpat, bz2, lzma and _elementtree reports no leaks.

🟡 Non-blocking

  • test_shutil on Windows (likely, not verified): upstream's bpo-9949 commit (75e0649) also changed TestMove.test_move_dangling_symlink. Its os.name == 'nt' branch compares realpath(src) with os.readlink(dst_link). Now that realpath resolves, for example expanding 8.3 short names in the temp dir, that assertion can fail on Windows with symlinks enabled. Porting that hunk, which uses realpath on both sides, avoids it.
  • ntpath.realpath and junctions: 3.7's readlink raises ValueError on a junction. A junction whose target is missing is therefore left unresolved in the non-strict fallback; existing junctions resolve through _getfinalpathname.
  • pyexpatns.h: it lacks the XML_SetAllocTrackerActivationThreshold / XML_SetAllocTrackerMaximumAmplification renames that 3.10.22.x, 2.7 and upstream have. 3.9.25.x lacks them too. pyexpat doesn't call them, so the risk is negligible.
  • pythongh-97514 wording: the NEWS and whatsnew entries imply 3.7.17.7 used Linux abstract sockets, but 3.7's arbitrary_address('AF_UNIX') always used a filesystem path, so 3.7 wasn't exposed.
  • pythongh-151497: the tarfile unbounded pre-allocation from oversized GNU/pax extended-header sizes. Upstream backported it only to 3.13 and 3.14, and 3.9.25.x lacks it too. It's a memory DoS worth a look for both lines.
  • os.mkdir docstring: it still says "The mode argument is ignored on Windows."

serhiy-storchaka and others added 7 commits October 29, 2026 13:51
… HTMLParser (pythonGH-137837) (pythonGH-140842) (pythonGH-140857)

(cherry picked from commit a17c57e)
(cherry picked from commit 0329bd1)

Co-authored-by: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
(cherry picked from commit 941811f)
… after free `list` (pythonGH-121345) (pythonGH-140834)

(cherry picked from commit 8334a1b)
(cherry picked from commit 0cd888b)

Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com>
Co-authored-by: Nikita Sobolev <mail@sobolevn.me>
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
(cherry picked from commit 42762bb)

3.7.17.x: test_list.py conflicted only because 3.7 has no
test_preallocation test; just the two new tests are added.
…work (pythonGH-134063) (pythonGH-134481)

(cherry picked from commit f3fc0c1)

Co-authored-by: Mike Salvatore <mike.s.salvatore@gmail.com>
(cherry picked from commit 03ac445)

3.7.17.x: test_ipaddress.py conflicted only on surrounding context (3.7
lacks the newer tests above the insertion point); the two new tests are
added unchanged.
The test_shutil and test_discovery hunks of upstream 75e0649 (bpo-9949,
pythonGH-15287), which the ntpath.realpath port left out:

- test_shutil.TestMove.test_move_dangling_symlink compares realpath() on
  both sides; with a resolving realpath the Windows-only readlink()
  comparison can differ (for example 8.3 short names in the temp dir).
- test_discovery.test_detect_module_clash substitutes abspath() for
  realpath() on Windows, since realpath() may add path prefixes when it
  cannot resolve the test's fake files.

The test_os hunk is not included: it relies on 3.8's bytes support in
os.readlink() on Windows, which 3.7 does not have.

(cherry picked from commit 75e0649)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pyexpatns.h prefixes the bundled Expat's exported symbols with PyExpat_ so
they cannot clash with a system libexpat loaded in the same process. Expat
2.9.0 added XML_SetAllocTrackerActivationThreshold and
XML_SetAllocTrackerMaximumAmplification (pythongh-90949, CVE-2025-59375) and
XML_SetHashSalt16Bytes, but the header did not rename them. The first two
match upstream and 3.10.22.x; pyexpat calls XML_SetHashSalt16Bytes, which
upstream does not rename yet either.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The ported fixes brought their version notes with them: 'next' (which
needs the newer Sphinx extension from pythongh-121277, so 3.7's docs would print
it literally) and the 3.9.x release each fix first shipped in. Use
3.7.17.8, the first 3.7 release that has them, and reword the ipaddress
leading-zeros note the same way. The 3.8.20 notes predate this release
and are left alone.

Also update the os.mkdir() docstring, which still said that mode is
ignored on Windows: since the pythongh-118486 port, a mode of 0o700 restricts
the new directory to the current user and administrators. Clinic output
regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…apply

- What's New for 3.7.17.8: add pythongh-137836 (HTMLParser raw-text elements),
  pythongh-120298/pythongh-120384 (list comparison and slice assignment) and
  pythongh-134062 (IPv4Network/IPv6Network hashes), and say the bundled certifi
  belongs to pip 24.0.post4 rather than 24.0.post3.
- pythongh-97514 (CVE-2022-42919): 3.7's multiprocessing has always given
  AF_UNIX listeners a filesystem path, so the upstream commit brought only
  its NEWS entry, whose text said 3.7 had used abstract sockets. Reword the
  entry and the What's New bullet to say 3.7 is not affected.
- Spell CVE ids as plain text in NEWS entries: 3.7's docs have no :cve:
  role.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@icanhasmath

Copy link
Copy Markdown
Author

Thanks. All three missing fixes are in now, and so are most of the non-blocking items. New commits, e1800cce7df..83ed74872e2:

Missing fixes

  1. Support other RAWTEXT and PLAINTEXT elements in HTMLParser python/cpython#137836: cherry-picked from 3.9.25.x (30c75a32c88). It applied cleanly. Lib/html/parser.py now matches 3.9.25.x, apart from the deprecated unescape() method that 3.7 still has.
  2. Use After Free in list_richcompare_impl  python/cpython#120298 / Array out of bounds assignment in list_ass_subscript python/cpython#120384: cherry-picked (ebd2dab06ea). The only conflict was test_list.py: 3.7 has no test_preallocation, so only the two new tests are added.
  3. Excessive hash collisions in IPv4Network and IPv6Network classes python/cpython#134062: cherry-picked (4dbfe1eb2bc). The conflict was test context only.

On 3.7.17.7 those three still collide, mis-parse and segfault; on this branch they're fixed.

These three had no PSF advisory and aren't in a Security NEWS section, and my audit was built from advisories, which is how it missed them. I then rechecked every Security NEWS entry in 3.9.18–3.9.25 against this branch. All are covered: the expat upgrades are superseded by 2.9.0, pythongh-121957 is N/A, and CVE-2023-40217 and CVE-2024-6232 were already in 3.7.17.7.

Non-blocking

The PR description has the test runs for these commits.

@ezequielp-activestate ezequielp-activestate left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed e1800cce7df..83ed74872e2. Approving.

The three missing fixes

  • pythongh-137836 (30c75a32c88), pythongh-120298/pythongh-120384 (ebd2dab06ea) and pythongh-134062 (4dbfe1eb2bc) match their 3.9.25.x counterparts line for line, apart from test context.
  • I built 83ed74872e2 on Linux and ran test_list, test_ipaddress and test_htmlparser against the fixed code and against the e1800cce7df versions of listobject.c, ipaddress.py and html/parser.py:
    • With the old code, test_list segfaults, and test_ipaddress and test_htmlparser fail.
    • With the fixes, all three pass.

Follow-ups

  • The test_shutil and test_discovery hunks are identical to 75e0649.
  • The pyexpatns.h renames are correct. XML_SetHashSalt16Bytes is called from both pyexpat.c and _elementtree.c, so it needs the rename too. Agreed that 3.9.25.x and 3.10.22.x should get it as well.
  • The docs version notes, the clinic regeneration, the pythongh-97514 note and the :cve: removal all look right. CVE-2026-12345 matches what upstream uses for pythongh-157579.

Tests
On a Linux build of 83ed74872e2, these 17 modules all pass: test_list, test_htmlparser, test_ipaddress, test_pyexpat, test_xml_etree, test_xml_etree_c, test_sax, test_minidom, test_os, test_shutil, test_unittest, test_userlist, test_tempfile, test_tarfile, test_ntpath, test_posixpath, test_html.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.