eMudhra's CA Keys Were Guessable: Update the Trust Stores Your Servers Use

Written by the Rafter Team

As of October 22, 2026.
Chrome and Firefox users were protected from this one the day it was reported.
Your backend is the open question: the fetch, requests and curl calls your services make to other services trust whatever CA bundle they shipped with, and many of those bundles still trust a certificate authority whose keys anyone can compute.
What happened
On October 17 an independent researcher reported to the Apple, Chrome, Microsoft and Mozilla root programs that the private keys of eight eMudhra intermediate CA certificates had been compromised, with a signed proof for each. Mozilla recovered the keys itself within two hours, "without any knowledge of the method the original reporter used."
The flaw was in key generation. A P-384 private key should be a random number about 384 bits long. Mozilla's Dennis Jackson found that all eight "used integers less than 256," so anyone can find them by generating the first 256 keys and comparing. Scott Helme lists the values; one key is the number 4.
Six of the eight intermediates issue TLS certificates; two sign code. All were created on April 30, 2025, and Sectigo's AAA Certificate Services root cross-signed them in May 2025, so each key sits behind two certificate paths, sixteen certificates in all (list). Whoever holds one of these keys can sign a certificate for any domain, and any client trusting the chain will accept it.
The response, from the Mozilla incident bug and Jackson's disclosure page:
- October 17: Firefox blocked the intermediates through OneCRL at 22:59 UTC; Chrome's CRLSet blocked them the same evening.
- October 18: eMudhra revoked its eight certificates.
- October 19: Sectigo revoked its eight cross-signs. Apple began blocking, though Jackson's page says some Apple devices were still unprotected as of October 22.
- October 20: Microsoft platforms started blocking. After several people recovered the keys on their own, Mozilla announced the emergency removal of trust in eMudhra's root,
emSign ECC Root CA - G3, and Chrome said it would do the same in Chrome Root Store version 43. - October 22: eMudhra announced it is leaving the global TLS certificate business.
eMudhra's chairman says no end-entity certificates were issued from the affected CAs and that its infrastructure was not compromised. Jackson's page says there are no Certificate Transparency entries for the intermediates in the vulnerable period, so browsers that enforce CT could not have been attacked. Neither claim covers the clients below.
Who is exposed
Browsers check revocation through their own blocklists and refuse certificates that were never logged to CT. Most other TLS clients do neither. Helme puts it plainly: curl, Python, Node, Go, Java and package managers "trust a CA bundle on disk, they don't check revocation by default, and they don't check CT." For them, the only fix is a new trust store or a new runtime.
That makes three groups:
- Your server-side HTTPS clients. Any service, job or CI step that calls an API over HTTPS. An attacker who can intercept that traffic can present a forged certificate and read or change what passes through it.
- Sites with eMudhra certificates under the ECC G3 root. Once Mozilla and Chrome finish the removal, those certificates stop working. eMudhra told Mozilla about 30,000 certificates need migrating and that about 97% came through ACME, so most of the fix is pointing an ACME client at a different CA.
- Anything on Apple platforms until Apple's blocking is complete.
The trap is that runtimes do not share one trust store.
Node.js ships its own bundled roots and ignores the operating system's by default.
Python's requests uses the certifi package, while the standard library on Linux uses the system store.
Java has its own cacerts.
Updating ca-certificates on the host fixes some of these and leaves the rest trusting the compromised keys.
We saw this on one of our own Ubuntu machines on October 22.
With the patched ca-certificates package installed, curl and Python's urllib rejected Jackson's test host.
On the same machine, requests with a February certifi and Node.js 20 both connected to it without complaint.
Fixes that have shipped
Jackson's page tracks patched versions across distributions, runtimes and tools. A few that most web stacks touch:
- Node.js 22.23.4, 24.22.1 and 26.12.1 (October 21) update the bundled roots to NSS 3.131.1 and reject chains containing blocked public keys. Node 20 reached end of life on April 30, 2026, and is not on that list.
- Python: certifi 2026.10.19, plus new Python, pip and uv releases.
- Rust:
webpki-roots1.0.10. - Distros: updated
ca-certificatesfor Debian, Ubuntu, Alpine, Fedora and Arch, among others. - Go and Java have new releases on the same list. Go on Linux reads the system store, so the distro package matters there too.
- Cloudflare Tunnel users should upgrade
cloudflaredto 2026.10.2, including in container deployments.
What to do now
- Test each client from where it runs. Jackson's test hosts serve certificates from the compromised intermediates. A certificate error is the good result. Run the check inside each container image and CI runner, with the HTTP library your code uses:
# Each of these should FAIL with a certificate error.
curl https://dv-g3b-emudhra.we-have-a-problem.com/
curl https://dv-g3b-aaa-emudhra.we-have-a-problem.com/ # Sectigo cross-sign path
python3 -c "import requests; requests.get('https://dv-g3b-emudhra.we-have-a-problem.com/')"
node -e "fetch('https://dv-g3b-emudhra.we-have-a-problem.com/').then(() => console.log('STILL TRUSTS'), e => console.log('rejected:', e.cause?.code))"
- Update the runtime and the trust store, then rebuild. Upgrade Node,
certifi, the JDK and the distroca-certificatespackage to the patched versions listed above or on Jackson's page. A base image built last week still has last week's bundle, so rebuild and redeploy images rather than patching hosts alone. Move anything on Node 20 to a supported line. - Check who issued the certificates you serve. If the issuer names eMudhra or emSign, get a replacement from another CA now:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -issuer -enddate
- Look for pinned or vendored bundles. Code that sets its own CA file, a
NODE_EXTRA_CA_CERTSpath, acacert.pemchecked into a repo, or a copy baked into an appliance will not pick up any of the updates above. - Keep TLS verification on. A client with
verify=False,rejectUnauthorized: falseorInsecureSkipVerifywas exposed before this incident and stays exposed after it.
A second CA problem the same week
Unrelated to eMudhra, GoDaddy reported on October 15 that 404,607 certificates from its GoDaddy and Starfield hierarchies did not match the profiles in its published policy, and it missed the revocation deadline.
Most are Starfield DV certificates.
GoDaddy's help page says the certificates were revoked on October 21 and that customers must download and install the reissued certificate themselves.
If the openssl command above shows Starfield or GoDaddy as the issuer, check that the certificate your server presents is the new one.
The trust store is a dependency
This incident shows how the web's certificate system is supposed to fail. A researcher found the flaw, root programs had browsers blocked within hours, and the CA is leaving the business. As of October 22, nobody in the incident record has reported a forged certificate in use.
The part that moved slowly is outside the browser. Every container image, runtime and vendored bundle carries its own copy of the list of who to trust, and that copy changes only when someone rebuilds it. Treat the CA bundle like any other dependency in the image: track its version and rebuild when it changes. The inventory that made PHP2Shell manageable answers this one too.