The exit is the headline, not the fix
On 22 October, eMudhra announced that its Board had decided to "voluntarily withdraw from the global SSL/TLS certificate business". The company puts that business at "about 1% of the global revenue", says the affected CAs were revoked "within 14 hours of discovery", and promises revocation and status services will keep running "until every issued certificate has expired or been replaced". Its G1 RSA roots stay in service during the transition, affected customers get free replacement certificates from partners, and its DSC, eSign, enterprise PKI and identity products carry on as before.
That is a tidy corporate ending. It changes nothing about the machines you run. The broken intermediate certificates are still sitting in every trust store that has not been updated, and an off-the-shelf tool now exploits exactly that. If your mental model is "the browsers handled it", this piece is for you.
Eight keys, eight bits
The details are almost comic. Scott Helme's write-up lists eight affected intermediates: six TLS issuing CAs covering DV, OV and EV in the G3B and G3C generations, plus two code-signing CAs. All were created in April 2025 and all were cross-signed by Sectigo's "AAA Certificate Services" root in May 2025.
They are P-384 keys, which should mean a private scalar of roughly 384 bits. The actual private keys were 156, 230, 115, 56, 155, 4, 66 and 237. Every one is below 256, so each fits in a single byte, and anyone holding the public certificate can recover the private key in under a second by simply trying every candidate.
eMudhra's explanation, as reported by TNW, is that a key generation ceremony on 30 April 2025 included a wrap/unwrap step that produced a second set of weak keys, and those weak keys were the ones that ended up in root stores. The company says no certificates were issued from the affected CAs.
That last point is less reassuring than it sounds. It does not matter what eMudhra issued. What matters is what anyone else can now issue, and the answer is "a certificate for any hostname, signed by a CA your software may still trust".
Firefox fixed it in under three hours. Your CI runner did not
Mozilla's response was fast. According to its security blog, it received the report on Saturday 17 October at 20:06 UTC and had a OneCRL block in place for standard Firefox configurations by 22:59 UTC. It then shipped Firefox 158.0.1, ESR 115.43.1, ESR 153.5.1 and NSS 3.131.1, which removes the root that signed the intermediates. Mozilla notes that the NSS change also protects "other applications that use Mozilla's trust store or versions derived from it".
That speed hides the real problem. Browsers have a push channel for revocation, and most other TLS clients have nothing like it. Helme puts it plainly: curl, Python, Node, Go, Java and git, in their default configurations, "trust a CA bundle on disk, they don't check revocation by default, and they don't check CT". Devices on frozen firmware "will trust these certificates until expiry, which is July 2039".
So the exposure is everything that is not a browser: API clients in your services, webhook senders, package installers on build agents, scripts that call requests or fetch, Go binaries compiled months ago, and container images built from a base layer nobody has refreshed since spring.
Exploitation no longer takes skill. mitmproxy merged an --emudhra option (PR #8500) whose help text reads "Sign certificates with a compromised eMudhra intermediate CA key." Any client that still trusts the eMudhra roots will accept mitmproxy's certificates without anyone installing mitmproxy's own CA. Someone with a position on the network path, such as a hostile Wi-Fi network, a compromised router or a shared CI network, can read and alter your TLS traffic with a command-line flag.
The audit: run this today
SafeDep's response guide is the most practical reference so far. Here is the short version, organised so you can work through it host by host and image by image.
1. Probe with curl
SafeDep runs two test hosts. Run both from every environment you care about, including inside your containers rather than only on the host:
curl -s -o /dev/null https://dv-g3b-emudhra.we-have-a-problem.com; echo "exit: $?"
curl -s -o /dev/null https://dv-g3b-aaa-emudhra.we-have-a-problem.com; echo "exit: $?"
Exit code 0 means the connection succeeded and that environment is affected. Exit code 60 means certificate verification failed, which is the result you want. This tests the system bundle curl uses. Language runtimes often ship their own bundles, so a clean curl result does not clear your Python or Node processes.
2. Check the runtimes that bring their own bundle
SafeDep lists these fixed versions:
- Python: certifi 2026.10.19 or later.
- Node.js: 22.23.4, 24.22.1 or 26.12.1. Node 20 and older get no fix, which makes this a good moment to finish that upgrade.
- Go: 1.26.10+ or 1.27.3+. Updating the toolchain is not enough on its own: you have to rebuild the binaries. Go 1.25 gets no fix.
- Rust: webpki-roots 1.0.10.
As of 22 October, SafeDep listed no fix yet for Bun, Erlang certifi or Bottlerocket. If you depend on any of those, track them and plan a workaround rather than assuming a fix will arrive in time.
python -c "import certifi; print(certifi.__version__)"
node --version
go version
go version -m ./your-binary | head -1
For Java, check which trust store your JVMs actually load and when it was last updated, and treat it like any other dependency. Then update the OS ca-certificates package on every host and base image.
3. Rebuild images, do not just patch hosts
SafeDep's warning deserves to be on a sticky note: "A host upgrade does not change an image that is already built". Every image carries its own copy of the CA bundle in whatever layer last touched it. Rebuild with a fresh base:
docker build --pull --no-cache -t your-service:latest .
Then redeploy, and run the curl probe inside the new container to confirm it.
4. Check by fingerprint, not by name
If you write a scanner that looks for the offending root or intermediates, SafeDep advises against matching on the certificate's name. Compare SHA-256 fingerprints instead. Names can be duplicated or reused, but fingerprints cannot.
The lesson: trust stores are dependencies
When this breaks things, and replacing about 30,000 certificates (eMudhra's own estimate, cited by iTnews) will break things, someone on your team will be tempted to make the errors go away with verify=False, NODE_TLS_REJECT_UNAUTHORIZED=0 or InsecureSkipVerify. Cloudflare's advice, quoted in the same article, is the right one: "It's important to not resolve these errors by disabling verification." Turning off verification during an incident like this one swaps a narrow exposure for a total one.
The broader point is about patch cadence. Most teams track CVEs in their libraries and have a process for shipping fixes within days. Almost none treat the CA bundle the same way, even though it decides who your software believes it is talking to. This incident is the case for changing that:
- Add
ca-certificates, certifi, webpki-roots and your runtime versions to the same dependency tracking you use for everything else. - Rebuild container images on a schedule, not only when application code changes, so base-layer fixes actually reach production.
- Keep the curl probe, or one like it, in a CI smoke test for as long as the test hosts stay up.
- Inventory devices on frozen firmware now. If they will trust these keys until 2039, they need network controls, not hope.
eMudhra leaving the market is the end of its story. For your systems, it is the start of a cleanup you have to do yourself, and the browsers will not do it for you.




Comments (0)
No comments yet. Start the conversation.