
CVE-2026-115557 is a critical CPython ssl issue addressed by adding a denylist for known compromised eMudhra intermediate certificate keys. The Python Software Foundation’s CVE Record assigns a CVSS 4.0 score of 9.4. Corrected Python releases automatically reject the known compromised keys even when certificate revocation is not configured.
This is a TLS trust failure, not a Python interpreter remote-code-execution vulnerability. The operational risk is that an affected TLS client could accept a certificate chain involving a compromised intermediate key, enabling an attacker in a suitable network position to impersonate services, observe protected data or alter traffic. Remediation must cover the interpreter, package-level CA bundles, installers, virtual environments, container layers and the trust store actually used by each workload.
CVE-2026-115557 fixed Python releases
| Python line | Affected versions in the CVE Record | First corrected release |
|---|---|---|
| 3.11 | Earlier than 3.11.18 | 3.11.18 |
| 3.12 | Earlier than 3.12.16 | 3.12.16 |
| 3.13 | Earlier than 3.13.18 | 3.13.18 |
| 3.14 | Earlier than 3.14.10 | 3.14.10 |
| 3.15 | Earlier than 3.15.2 | 3.15.2 |
| 3.16 development series | 3.16.0 alpha builds before 3.16.0 | Use a current corrected development build or final release |
Python 3.15.2 and 3.14.10 were published with binary installers. The Python release announcement describes 3.13.18, 3.12.16 and 3.11.18 as source-only security releases. Distribution packages and embedded runtimes may use backports or vendor-specific version strings, so compare them with the applicable vendor advisory rather than assuming an upstream string is the only valid fix.

Explore Penligent for authorized security testing
What changed inside CPython ssl
The CPython patch adds an extraordinary defense-in-depth check during certificate verification. It matches the public key using the SHA-256 digest of the RFC 5280 SubjectPublicKeyInfo. Matching the key, rather than only a certificate serial number or issuer string, means a cross-signed certificate that reuses a compromised key can also be rejected.
The patch discussion is explicit that this built-in denylist does not replace an updated operating-system, container or application trust store. Its purpose is to block the known keys while normal trust-store and package updates propagate through environments that may otherwise remain stale.

Explore Penligent for authorized security testing
Do not collapse five trust boundaries into one checkbox
| Layer | What it controls | Why a separate check is required |
|---|---|---|
CPython ssl | Built-in rejection of the known compromised public keys | An older interpreter lacks the defense even if another Python on the host is fixed |
| Operating-system CA store | System trust anchors and distrust updates | Containers and application bundles may not inherit the host store |
certifi | A Python-distributed CA bundle used by many clients | Virtual environments can preserve old copies independently |
| pip and uv | Package-download TLS behavior and bundled dependencies | Installer behavior can differ from an application’s TLS stack |
| Container or application image | The interpreter, packages and CA files actually deployed | Layer caching can retain vulnerable artifacts after a build file changes |
The Python incident guidance recommends certifi 2026.10.19 for compatibility with unaffected emSign roots and says existing virtual environments should update pip and uv. It identifies pip 26.2.2 as the corrected minimum in this incident response. Consult the linked incident guidance when selecting current package versions.
Inventory the interpreter and trust path in the running workload
Run checks inside the same container, virtual environment, service account or job that makes the TLS connection. The shell’s default Python can differ from the executable launched by a systemd service, application server, CI runner or packaged desktop application.
python -VV
python -c 'import sys, ssl; print(sys.executable); print(sys.version); print(ssl.OPENSSL_VERSION); print(ssl.get_default_verify_paths())'
# Show the active environment and package versions
python -m pip --version
python -m pip show certifi pip 2>/dev/null
# If certifi is installed, show the bundle selected by that package
python -c 'import certifi; print(certifi.__version__); print(certifi.where())' 2>/dev/null
Record the executable path, Python version, virtual-environment path, OpenSSL version, default verification paths, certifi version and bundle location. Absence of certifi does not prove safety: the application may use the system store, a framework bundle, a custom SSLContext, an injected CA file or a native library outside Python.
Find stale virtual environments and immutable images
Virtual environments copy or reference an interpreter and contain their own packages. Updating the base operating system does not automatically replace every interpreter or certifi wheel. Inventory production services, CI runners, scheduled jobs, developer tooling used for releases and long-lived automation environments.
For containers, record the image digest rather than only the tag. Rebuild with refreshed base images and package indexes, and bypass stale layers when necessary. Then redeploy and prove that the running task, pod or function uses the new digest. A successful registry push does not change an already running container.
Remediation sequence
- Map each workload to its actual Python executable, virtual environment, image digest and TLS client library.
- Upgrade CPython to 3.11.18, 3.12.16, 3.13.18, 3.14.10, 3.15.2 or a later corrected release, as applicable.
- Apply the operating-system or distribution CA update.
- Update
certifi, pip and uv according to the current Python incident guidance. - Rebuild application and CI images so old CA bundles and installer versions are not retained in cached layers.
- Redeploy or restart every workload that holds the old interpreter or trust data in memory.
- Repeat the inventory commands inside the running deployment and retain the output.
- Test approved TLS-dependent workflows with certificate and hostname verification enabled.
Do not use verify=False, an unverified SSLContext, disabled hostname checks or a catch-all imported root as a compatibility workaround. Those changes can make a failing connection appear restored by removing the security property under repair.
Verification matrix
| Question | Strong closure evidence |
|---|---|
| Is CPython corrected? | Running process uses a corrected upstream release or documented vendor backport |
| Are CA bundles corrected? | Current OS trust update and current application bundle are present |
| Are installers corrected? | Active virtual environments report the approved pip and uv versions |
| Was the deployment replaced? | New image digest or artifact is active in every instance |
| Does TLS still work securely? | Authorized business flows succeed with verification enabled |
| Was earlier exposure assessed? | Relevant proxy, DNS, certificate, package and identity evidence was reviewed |
Relationship to Go and Java eMudhra fixes
The same certificate incident produced different implementation tasks across ecosystems. The Go CVE-2026-111943 response and the Oracle Java eMudhra trust fixes require their own runtime updates and deployment evidence. A Python update does not repair Go or Java, and the fixed-version boundaries are not interchangeable.
Incident review
A vulnerable interpreter or stale CA bundle is a remediation finding, not proof that a malicious certificate was presented. For sensitive services, review outbound proxy and network telemetry, observed certificate chains where available, DNS changes, package-download history, integrity records and identity events for the relevant period. Preserve hashes and provenance for packages acquired during the exposure window.
Conversely, a normal application log without TLS errors does not prove the connection was safe. Successful verification is exactly what a compromised trust path could allow. Keep software state, trust-store state, observed certificate evidence and signs of malicious activity as separate conclusions.
Conclusion
CVE-2026-115557 requires more than a single package update. Move each workload to a corrected CPython release, update the applicable CA stores and Python packages, rebuild virtual environments and images, restart the actual deployment and validate TLS with verification enabled. The decisive evidence comes from the running interpreter, the trust path it uses and the artifact digest now serving production traffic.
The following video introduces a general Penligent workflow. It is not a demonstration of the eMudhra certificate incident.

