eMudhra CA compromise: eight intermediate keys anyone could recover
Eight eMudhra intermediate CA keys were generated with almost no randomness. What happened, which root was distrusted, and which clients stayed exposed after browsers were fixed.
By the Maborak engineering team · · 7 min read
The private keys of eight eMudhra intermediate certificate authorities could be recovered by anyone from the public certificates. Six of them were TLS intermediates chaining to emSign ECC Root CA – G3, a root trusted by Mozilla, Chrome, Apple and Microsoft. With one of those keys, an attacker could issue a certificate for any domain that those trust stores would accept. Browsers were protected within days; software that reads a CA bundle from disk was protected only once that bundle was updated.
Checked 29 October 2026. The account below is taken from Mozilla’s incident bug, the disclosure site’s published certificate data, Canonical’s notice and the PyPI release record, linked under Sources. Statements by eMudhra are marked [vendor]; findings posted by third parties in the bug are marked [reported].
Background
The keys come from a key ceremony on 30 April 2025 that produced 24 intermediates: three series (A, B and C), two algorithms (RSA-4096 and P-384) and four purposes (DV, OV and EV TLS, plus code signing). The eight weak keys are all the P-384 keys in the B and C series. Sectigo cross-certified them from its AAA Certificate Services root on 14 May 2025. eMudhra states that no end-entity certificates were issued from them. [vendor]
There was an earlier sign. In June 2025, Mozilla Bug 1970728 recorded that eMudhra had published CRLs for the same TLS intermediates with signatures that did not verify against the intermediates’ keys.
| Date (UTC) | Event |
|---|---|
| 30 Apr 2025 | Key ceremony creates the eight weak keys |
| 14 May 2025 | Sectigo issues AAA cross-certificates for all eight |
| 17 Oct 2026, 18:05 | Key recovery reported to the root programs; Firefox (OneCRL) and Chrome (CRLSet) block the intermediates |
| 18 Oct, 09:24–09:38 | eMudhra revokes the eight intermediates |
| 19 Oct | Sectigo revokes the cross-certificates; Mozilla notifies downstream trust stores |
| 20 Oct | Public disclosure. Mozilla removes trust in emSign ECC Root CA – G3 and Chrome commits to the same. Microsoft blocks the intermediates. Ubuntu ships ca-certificates 20260816; certifi 2026.10.19 reaches PyPI |
| 20–21 Oct | 107,107 certificates signed with six of the keys appear in Certificate Transparency logs, issued by third parties [reported] |
| 22 Oct | Apple blocks the intermediates in its products |
| 26 Oct | macOS 27.2 ships without a fix for the command-line tools Apple bundles [reported] |
eMudhra stopped issuing from every intermediate under emSign ECC Root CA – G3 on 20 October, estimated about 30,000 certificates needing migration (most issued through ACME), and moved those subscribers to its RSA root, emSign Root CA – G1. Mozilla kept trust in G1 “at this time”. eMudhra later announced it would leave the public TLS certificate business. [vendor]
Mechanics
A P-384 private key is meant to be a random integer between 1 and the order of the curve, a number close to 2^384. The public key is derived from it, and working backwards is infeasible only because the integer is unpredictable. Mozilla’s analysis found that the eight private keys were all integers below 256: every byte except the last was zero, so the keys could be found almost immediately from the public certificates. The A series and its replacement did not show the flaw. [vendor]
expected: private key = random integer in 1 .. ~2^384
observed: private key < 256 for all eight B/C series P-384 keys
effect: private key recoverable from the published certificate
The root cause is still open. The bug discussion points at an approved wrap and unwrap test step added to the ceremony, with the cross-signing requests created from the re-imported key objects instead of the keys generated in the HSM. eMudhra has not yet published the ceremony script or logs. [reported]
Two chains led to the compromised intermediates, and each was closed differently:
leaf ─ EM DV/OV/EV TLS CA - G3B/G3C ─ emSign Root TLS CA - G3 ─ emSign ECC Root CA - G3 (Mozilla, Chrome, Apple, Microsoft)
leaf ─ EM DV/OV/EV TLS CA - G3B/G3C ─ AAA Certificate Services (Apple, Microsoft)
emSign Root TLS CA – G3 is itself a root only in Microsoft’s store. In Mozilla-derived bundles it is reached through a certificate signed by emSign ECC Root CA – G3, so removing ECC G3 breaks the first chain. Mozilla and Chrome had already removed AAA Certificate Services, so the second chain affected only stores that still carry it.
Impact
An attacker holding one of the keys can intercept TLS for any hostname, for any client that still trusts the chain. Who was exposed depended on how the client gets its trust decisions:
- Browsers enforce Certificate Transparency, and no certificate from these intermediates was in a CT log before disclosure. The disclosure site concludes that Firefox, Chrome, Edge and Safari could not have been attacked silently. They also received pushed blocks from 17 October.
- Clients reading a PEM bundle (curl, git, Python with
certifi, Go and OpenSSL programs, container images) do not enforce CT and usually do not check revocation for intermediates. They stayed exposed until their bundle dropped emSign ECC Root CA – G3. - Bundles frozen at build time stay exposed until rebuilt: container images, vendored
certifi, Electron apps such as Slack and Discord, and Javacacertsfiles.
After disclosure, third parties used the keys. The 107,107 certificates logged on 20 and 21 October include one for emsign.filippo.io with valid embedded SCTs, precertificates for emudhra.salesforce.com, and 106,050 proof-of-concept certificates naming google.com. Almost none carry a revocation pointer, so a client that checks revocation only for the end-entity certificate finds nothing to check. [reported]
Mitigation
- Update the trust store. On Ubuntu,
ca-certificates 20260816(sudo apt update && sudo apt install --only-upgrade ca-certificates 'libnss3*'); Canonical lists the fixed version for each release. For Python,certifi 2026.10.19or later. Update Electron apps and browsers. - Rebuild what carries its own copy. Container images built before 20 October keep the old bundle until rebuilt. Images on an unsupported base release may never receive the package fix; disable the root explicitly there, as Argo CD did for its 3.3 images, by prefixing
mozilla/emSign_ECC_Root_CA_-_G3.crtwith!in/etc/ca-certificates.confand runningupdate-ca-certificates. - Java on Ubuntu. The Java store does not follow the system update automatically. Canonical’s procedure:
sudo rm -f /etc/ssl/certs/java/cacertsthensudo update-ca-certificates --fresh, and re-add any local CAs afterwards. - macOS command-line tools. Apple’s fix covers Safari and apps on its networking framework, not the
git,curlandpython3it ships. Until Apple updates/etc/ssl/cert.pem, point those tools at a bundle without the two roots, and recheck after every macOS update, which can revert a manual change. - TLS-intercepting proxies validate upstream certificates with their own store. Update the proxy, or every client behind it inherits the exposure.
Removing the root also breaks legitimate certificates that chain to it. That is intended: eMudhra’s subscribers under ECC G3 are being moved to its G1 hierarchy. Re-adding the root to restore a broken site is not a rollback to consider.
Verification
Check the bundle the software actually uses, not the package version. A package can be updated while an application keeps reading a vendored copy.
# system bundle (Debian/Ubuntu path; /etc/ssl/cert.pem on macOS)
grep -c "emSign ECC Root CA - G3" /etc/ssl/certs/ca-certificates.crt
# the bundle Python requests uses
python3 -c 'import certifi; print(certifi.__version__, certifi.where())'
# inside a running container
docker exec <container> grep -c "emSign ECC Root CA - G3" /etc/ssl/certs/ca-certificates.crt
A count of 0 means the root is gone from that bundle. Then check which bundle each tool loads (git config --get http.sslCAInfo, CURL_CA_BUNDLE, SSL_CERT_FILE, REQUESTS_CA_BUNDLE); an override can point to an older file. The disclosure site provides test hosts and offline test chains for confirming that a client rejects the compromised intermediates.
Sources
- Mozilla Bug 2083449, “eMudhra: Private key compromise of Intermediate Certificates” (opened 18 October 2026; comments 10, 11, 18, 19, 20, 44 cited above), and Bug 1970728 (June 2025).
- eMudhra Intermediate CA Compromise (20 October 2026, updated 28 October), with impacted-intermediates.json, roots.json and the macOS note.
- Mozilla dev-security-policy thread for trust-store operators.
- Canonical: eMudhra CA compromise fixes available (20 October 2026, updated 22 October) and USN-8944-1.
- certifi 2026.10.19 on PyPI (uploaded 20 October 2026, 02:24 UTC).
- Argo CD pull request #30349 (22 October 2026), an example of disabling the root in an image built on an unsupported base.