Overview
On October 20, 2026, Python’s security team advised users to update Python packaging tools following the eMudhra / emSign certificate authority incident. The immediate concern is the certificate trust used when those tools connect to package indexes and other HTTPS services. Python security announcement
Google confirmed that eight intermediate CA certificates had private keys generated with insufficient randomness. Anyone who recovers such a key can create certificates that impersonate websites to a client that still accepts the affected chain. An attacker must also intercept or redirect the victim’s connection to exploit that trust. Google’s incident report
For software delivery, the risk is straightforward: a dependency downloader could accept an attacker’s HTTPS response as authentic. This attack path does not require compromising the package registry itself. The disclosure’s authors say it remains unknown whether attackers exploited the weakness against non-browser clients. Coordinated disclosure
Action Required
Start with these upstream remediation versions, identified as of October 22, 2026. Check custom certificate bundles and distributor backports alongside the version numbers.
Sources: Python’s update list, pip changelog, uv advisory, and conda ecosystem guidance.
The certifi advisory identifies 2026.10.18 as the initial fix. Python recommends 2026.10.19 because it restores unaffected emSign roots while retaining the security change. Use 2026.10.19 or later for the upgrade target. certifi advisory, Python guidance
How the Certificate Trust Failed
A certificate authority signs certificates that clients use to authenticate servers. Intermediate CAs sit between a trusted root and the server certificate. Possession of an intermediate CA’s private key can therefore let an attacker issue certificates for services they do not operate.
Mozilla’s incident record identifies six affected TLS intermediates and two code-signing intermediates. It also records cross-signed versions, where the same keys can be reached through another certificate chain. That is why remediation must account for alternate chains, not just one certificate filename. Mozilla incident record
Browser vendors distributed blocks through their own revocation mechanisms. Google, for example, blocked the affected intermediate public keys through Chrome’s CRLSet. Developer tools do not necessarily receive or enforce those browser updates. A browser that rejects an affected chain says nothing conclusive about the Python process running beside it. Google’s response
Why Updating certifi Alone Does Not Fix pip
There can be several independent copies of certificate trust on one machine: the OS store, an application’s certifi installation, pip’s vendored certifi, and a tool’s embedded or explicitly configured bundle.
Upstream pip uses system certificates in addition to certifi by default in its current configuration. Updating the OS therefore does not necessarily remove trust supplied by pip’s bundled certificates. The 26.2.2 release specifically upgrades that bundled certifi to 2026.10.19. Updating the separate certifi package in a project does not replace pip’s vendored copy. pip certificate documentation, pip release notes
uv has a different configuration model. Its advisory says users of the default bundled roots need the update; users selecting system or custom certificates must verify that the selected store rejects the affected chains. uv advisory
Distribution packages may patch these defaults or backport fixes. Use the distributor’s security guidance for OS-managed Python installations, and inspect the actual environment rather than judging it solely by the upstream version number.
What We Verified
We tested the fourteen certificate chains published by the disclosure authors against three isolated CA bundles on October 22, 2026. The comparison used OpenSSL 4.0.3, with hostname and TLS-server-purpose checks enabled and default CA directory and store lookups disabled. It did not enable Certificate Transparency or online revocation checks.
The older bundle accepted all seven supplied paths through the emSign root, including the test certificate without a Certificate Transparency entry. It already rejected the seven AAA Certificate Services paths. Both corrected bundles rejected all fourteen.
Before and After the CA Bundle Update
For the same dv-g3b-emudhra.we-have-a-problem.com test chain, the older bundle produced this output:
With certifi 2026.10.19, verification failed with exit code 2:
The pip 26.2.2 wheel's vendored certificate bundle was byte-for-byte identical to certifi 2026.10.19 and produced the same rejection. We also verified the wheel against the SHA-256 digest in Python's security announcement before inspecting it.
These are local certificate-verification results, not attack telemetry. They demonstrate the trust change in the tested bundles; an application's system or custom trust configuration still needs its own check. The disclosure site supplies the certificate chains and verification instructions.
Am I Affected?
Run these checks with the interpreter used by the application or build job:
The last command reports the pip version bundled with that interpreter. Some distributors omit ensurepip. A missing standalone certifi package also does not establish that pip has no bundled CA store. ensurepip documentation, pip vendoring release notes
Build the inventory around execution environments: developer virtual environments, self-hosted runner images, job containers, build stages, and application containers making outbound HTTPS requests. Check tool copies installed through separate mechanisms, such as a standalone uv binary and one installed in a Python environment.
Inspect explicit trust configuration too, including PIP_CERT, REQUESTS_CA_BUNDLE, SSL_CERT_FILE, SSL_CERT_DIR, and uv’s system-certificate setting. Upgrading a package cannot repair an old custom bundle that the application continues to select. pip configuration, uv certificate configuration
Remediation Steps
Bootstrap a corrected pip securely
For an upstream pip installation on Python 3.10 or newer, Python’s security team provides this direct wheel URL with an expected SHA-256 digest. The digest binds the installation to the published wheel even when the existing pip’s TLS trust is suspect. Obtain the command through a trusted, updated browser or another trusted channel. Python’s secure update instructions
Repeat for each affected virtual environment. For OS-managed installations, apply the distributor’s fix through its package manager.
pip 26.2.2 requires Python 3.10 or later. An older interpreter that cannot install this release still needs remediation through a supported Python upgrade or an applicable distributor fix. pip release metadata
Update uv through a corrected trust source
For uv installed using its standalone installer, the following uses the operating system verifier during self-update:
Use this only after confirming that the system verifier rejects the compromised chains. For a package-manager installation, update through that package manager. Custom CA files require their own review. uv certificate configuration, uv upgrade instructions, Python discussion of uv bootstrapping
Update the Python installation that creates new environments
Upgrading pip inside one virtual environment does not update the wheel stored in the parent interpreter’s ensurepip module. That older interpreter can seed another environment with the old pip. Running ensurepip --upgrade only uses the bundled wheel; it does not download a current release. ensurepip documentation
We reproduced this distinction in a disposable Python 3.14.7 environment: after installing the verified pip 26.2.2 wheel, pip reported its updated certifi as 2026.10.19, while ensurepip.version() still returned 26.2.1. That seed belongs to the interpreter, not the upgraded virtual environment.
On October 21, Python released 3.15.1, 3.14.9, and 3.13.17, each bundling pip 26.2.2 and its updated certifi. Update the appropriate interpreter distribution and handle existing virtual environments separately. Until that is complete, make the corrected pip bootstrap an explicit step before new environments download application dependencies. Python emergency release announcement
Rebuild containers and refresh CI images
Update the Dockerfile’s Python tooling and OS CA packages, along with any dependency pins that would restore older versions. Select a corrected base image; if it is pinned by digest, change the digest explicitly.
Then rebuild:
Docker documents two separate effects: --pull checks for an updated base image, while --no-cache reruns build layers. Neither overrides an old version pin or repairs a Dockerfile that never updates the affected packages. Check both build and runtime stages, verify the resulting image, and replace deployed containers and runner images. Docker build guidance
Refresh cached virtual environments and tool installations that would reintroduce the old versions. Record the interpreter, package-manager versions, and rebuilt image digest in the remediation change.
Verify certificate rejection
The disclosure site provides affected-chain test endpoints and an offline chain bundle. Test with the actual client and trust configuration used in the workload, including cross-signed paths. A browser check or a curl check does not establish what pip or uv will accept. A timeout or DNS failure also does not prove certificate rejection. Verification resources
Keep TLS verification enabled. If a legitimate internal package index stops working after trust removal, replace its affected certificate chain. Bypassing verification would reopen the authentication problem the update is intended to fix. Google’s certificate migration guidance
Protect Dependency Downloads with Trusted Hashes
For pip workflows, maintain reviewed requirements with pinned versions and independently trusted SHA-256 hashes for every dependency. Enforce them during installation:
This command requires a requirements file that already contains the necessary hashes. Hashes learned from the same intercepted download do not provide an independent integrity check. Version pinning alone does not authenticate the downloaded bytes. pip secure-install guidance
When assessing exposure, distinguish an outdated trust store from evidence of an intercepted download. Investigate suspicious artifacts, unexpected process execution, and credential use if there are signs of exploitation. The existence of an affected CA bundle alone does not establish that an environment was compromised.
How StepSecurity Helps Secure CI/CD
Harden-Runner gives security teams visibility into outbound connections and correlates activity with CI workflow steps. Its network policies can restrict destinations, and its monitoring helps teams investigate unexpected behavior during dependency installation and builds. Harden-Runner documentation
Those controls complement corrected TLS trust and independently verified artifacts. A hostname allowlist alone cannot authenticate an HTTPS response when the client accepts a forged certificate for an allowed hostname. For this incident, updating the package managers and every trust store they use remains essential.
Start free with StepSecurity to monitor dependency-installation activity and investigate unexpected outbound connections in your CI workflows.



