Python Weekly #6: Python 3.15.2 Blocks Compromised Root CA, PEP 851 Proposes list.discard(), Mainline Accelerates Signal Polling and asyncio Stream Scanning

Python · Weekly #6

Python Weekly #6: Python 3.15.2 Blocks Compromised Root CA, PEP 851 Proposes list.discard(), Mainline Accelerates Signal Polling and asyncio Stream Scanning

pythonPythonWeeklyPEP 851Performance TuningRuntime Security

Sources:GitHub Releases + 官方博客 + HN

📦 Release Updates

Emergency Five-Branch Security Releases and Transport Layer Hardening

The current official stable release is Python 3.15.2 (officially released on Oct. 25, 2026, signed by Release Manager Hugo van Kemenade). For a complete breakdown of language and runtime features introduced in Python 3.15, see our in-depth feature article: Python 3.15 Deep Dive; for the prior stable generation, see Python 3.14 Deep Dive.

Triggered by the compromise of private keys belonging to intermediate CAs operated by eMudhra, the Python security team coordinated emergency out-of-band releases across five active maintenance branches. Key engineering adjustments include:

  1. Low-Level SSL Module Intercepts Compromised Keys (CVE-2026-115557 / gh-160040): Injected a hardcoded blocklist based on Subject Public Key Info (SPKI) hashes into the core _ssl C extension. This mechanism functions as a last-resort handshake guard: even if the host operating system’s root certificate bundle remains unpatched, TLS handshakes will immediately reject compromised certificate chains. Standard pip operations on unpatched hosts are protected against these MitM attack vectors.
  2. Path Traversal and Cookie Validation Fixes: All branches patched a vulnerability in tarfile.tar_filter where symbolic links could overwrite extraction targets (CVE-2026-114583 / gh-160097); merged gh-160300 to reject cookie headers carrying negative version numbers in http.cookiejar.
  3. Backports to Security-Only Branches: Source-only releases for 3.13.18, 3.12.16, and 3.11.18 incorporated bundled Expat 2.9.0 upgrades (CVE-2026-77214 / CVE-2026-102633), disabled Windows mimetypes.knownfiles by default (CVE-2024-3220), and resolved race conditions during concurrent tempfile.TemporaryDirectory cleanup (gh-157579).

Active maintenance branch status overview:

VersionOfficial Release DateBranch Type & PackagingCore Engineering Impact & Fixes
Python 3.15.2Oct. 25, 2026Current Stable Mainline (Bugfix, Binaries provided)Bundled _ssl blocks compromised SPKIs; incorporates ~130 stability and build fixes
Python 3.14.10Oct. 25, 2026Previous Stable Branch (Bugfix, Binaries provided)Synchronized hardcoded certificate blocklist, tarfile extraction filtering, negative cookie fix
Python 3.13.18Oct. 25, 2026Security-Only Maintenance (Source only)SPKI blocklist backport, Expat updated to 2.9.0, temporary directory cleanup race fixed
Python 3.12.16Oct. 25, 2026Security-Only Maintenance (Source only)SPKI blocklist backport, patched Windows MIME registry vulnerabilities and path traversal
Python 3.11.18Oct. 25, 2026Security-Only Maintenance (Source only)Mitigates MitM risks in legacy container deployments with outdated host CA bundles

Upgrading global Python binaries does not automatically update dependencies bundled inside existing virtual environments (virtualenv). Engineering teams should execute python -m pip install --upgrade certifi pip across deployed environments to refresh application-layer trust stores.


📝 Deep Dives

PEP 851 Submitted for Review: Introducing list.discard() to Eliminate Double Traversals and Race Conditions

  • What happened: On October 27, 2026, Stan Ulbrych submitted PEP 851 targeted for Python 3.16, proposing a native list.discard(value, /) method for built-in list and collections.UserList. If a matching item is found, it is removed and the method returns True; otherwise, it returns False without raising ValueError.
  • Why it matters: Addresses core limitations of existing safe removal idioms. The idiom if x in lst: lst.remove(x) traverses the list twice on a hit, and introduces a multithreaded race condition where the element could be removed between the check and the call, triggering a crash. Conversely, try: lst.remove(x) except ValueError: pass requires four lines of boilerplate, incurs exception construction overhead on misses, and risks accidentally swallowing business exceptions raised inside custom __eq__ implementations. The author scanned the top 5,000 PyPI packages, identifying 1,062 instances of conditional removals (across 411 libraries) and 331 try/except patterns (across 164 libraries), while standard library non-test code contained 27 occurrences. The implementation directly reuses remove()’s optimized C loop.
  • Who it affects: Library authors and application developers implementing thread-safe collections and event listener deregistration routines.

CPython Optimizes Signal Polling: Arithmetic and String Operations Accelerated by Over 20% (gh-157746 / PR #157748)

  • What happened: On October 31, 2026, PR #157748 submitted by Pieter Eendebak was merged into master. It overhauls the internal C API function PyErr_CheckSignals(), bypassing the signal handler iteration loop entirely via an atomic flag whenever no OS signals are pending for the current thread.
  • Why it matters: CPython invokes PyErr_CheckSignals() intensely within evaluation loops and tight operations (such as string formatting, large integer arithmetic, and I/O iterations) to maintain responsive interruption handling. Traversing handlers when no signals are pending is pure overhead. Official pybench results show: 10-digit multiplication a * b dropped from 159ns to 102ns (a 1.56x speedup), and integer division a // c gained 1.24x; str(12345) dropped from 68.6ns to 56.8ns (a 1.21x speedup); repr(list(range(100))) dropped from 3.06µs to 2.36µs (a 1.29x speedup); ', '.join(map(str, range(100))) sped up by 1.22x; and writing 100 rows of integers via csv.writer sped up by 1.21x.
  • Who it affects: Backend and data teams running intensive text serialization, logging generation, and high-precision numeric computations.

asyncio Overhauls Multi-Separator Stream Scanning: Buffered Read Throughput Surges up to 44x (gh-159500 / PR #159505)

  • What happened: On October 31, 2026, PR #159505 submitted by Cody Maloney was merged into master, overhauling the buffered matching algorithms in asyncio.StreamReader’s readline() and readuntil().
  • Why it matters: Protocol parsers frequently specify tuple separators (such as HTTP and SMTP matching (b"\n", b"\r\n")). The previous implementation repeatedly scanned the entire buffer for every separator in the tuple on every invocation. The new implementation introduces early termination: once a candidate separator’s match offset exceeds the best position already found, subsequent scanning for that separator is immediately truncated; single-byte delimiters on cached buffers also bypass redundant checks. pyperf benchmarks show: tuple readuntil() on pre-buffered data collapsed from 11.2µs down to 422ns (a 26.5x speedup); across 64 KiB chunks, latency dropped from 19.1µs to 430ns (a 44.5x speedup); and readline() gained 1.82x. Callgrind profiles recorded instruction counts per call dropping from 7,105 to 3,890.
  • Who it affects: Network systems developers authoring reverse proxies, protocol gateways, and streaming services on native asyncio.

CPython Corrects Slots Static Shared Keys: Single-Node Instance Memory Trimmed by 29.3% (gh-135385 / PR #156656)

  • What happened: On October 31, 2026, Serhiy Storchaka merged PR #156656 into master, correcting class initialization logic in _PyDict_NewKeysForClass() that incorrectly reserved inline dictionary keys for __slots__ attributes.
  • Why it matters: CPython 3.12 introduced shared dictionary keys for class attributes, recording self.X assignments from class bodies into __static_attributes__. However, attributes declared in __slots__ are accessed via fixed struct offsets and do not live in instance __dict__ storage. The previous logic failed to deduct the intersection, causing classes defining both __dict__ and __slots__ to allocate wasted inline dictionary slots on every instance. The fix significantly compresses memory for hybrid classes: in standard library xml.dom.minidom nodes (where 11 static attributes are all slots), individual node instance sizes shrank from 328 bytes to 232 bytes (a 29.3% reduction); the overall test suite footprint dropped from 120.4MB to 104.4MB, while class creation latency remained completely neutral.
  • Who it affects: Memory-intensive architectures constructing massive tree nodes, ASTs, and large in-memory object graphs.

🔥 Community Buzz

Experimental JIT Compiler Formally Exits CPython Master (HN 580 Points / 338 Comments)

On October 26, LWN confirmed that the experimental Copy-and-Patch JIT compiler introduced in Python 3.13 will be removed from the master branch at the start of the 3.16 cycle. Faced with the Steering Council’s mandate to satisfy 10 rigorous operational criteria—encompassing security auditing, tier-one platform parity, and real-world package ecosystem testing—the PEP 836 authoring team (Savannah Ostrowski, Brandt Bucher, Ken Jin) withdrew the proposal on October 19. The development provoked intense debate on Hacker News (580 points, 338 comments; HN Discussion / LWN Coverage).

The controversy divided the community into two distinct camps:

  • Engineering Pragmatism & Security Camp: Core maintainers and security researchers supported the Steering Council’s firm stance. Master cannot serve as an uncommitted proving ground without long-term maintenance guarantees. Dynamic machine code emission severely complicates debuggers, profilers, and low-level tracers while widening the attack surface (citing historical V8 type confusion vulnerabilities). Without proven end-to-end acceleration across popular PyPI dependencies, maintaining JIT machinery on trunk incurs unsustainable maintenance debt.
  • Performance Advocates: Enterprise software engineers and application developers expressed deep disappointment. Modern datacenters incur massive compute and energy costs running interpreted workloads, and rewriting hot paths in Cython or Rust is prohibitively expensive. Critics argued that the Council’s 10 criteria were unattainable for a largely volunteer effort; given PyPy’s ongoing C-extension compatibility challenges, an in-tree JIT remains Python’s only realistic avenue for architectural performance breakthroughs.

None Semantic Overload & PEP 661 Sentinel Values (HN 71 Points / 47 Comments)

On October 22, Florian Wilhelm published “Much Ado About None: Sentinel Values in Python”, reflecting on his EuroPython presentation alongside Python 3.15’s built-in sentinel() (PEP 661) and Pydantic 2.14’s stabilization of MISSING. The article explored how overloaded None semantics complicate static type systems, sparking discussion on Hacker News (71 points, 47 comments; HN Discussion / Article).

The debate centered around language design philosophy:

  • Functional Monad Advocates: Developers with background in Rust and advanced type systems argued that ad-hoc sentinels are a stopgap. Python should adopt native monadic constructs like Option<T> or Result<T, E> to cleanly separate absence from uninitialized state at the type level.
  • Pythonic Pragmatists: Mainline Python developers countered that monads fragment the existing dynamic ecosystem. PEP 661’s built-in sentinel() enables precise Type Narrowing in type checkers while resolving cross-module identity loss during unpickling and copying (which plagued legacy object() and singleton Enum tricks), striking an ideal balance within Python’s existing grammar.

🔭 Next Week in Focus

  1. CPython Mainline JIT Deletion PR: Following the withdrawal of PEP 836, the pull request executing the Steering Council’s removal directive will land on master. Track the excision of JIT code generation and Tier-2 executor stubs.
  2. PEP 851 Steering Council Review Assignment: Monitor the Council’s review schedule for the list.discard() proposal, including community discussions on extending similar APIs to collections.deque.