eMudhra CA Key Leak: What Went Wrong

8 eMudhra CA private keys were found to be smaller than 256, one of them literally the number 4. Researchers recovered them in under a second, and the keys had been weak since April 2025. eMudhra blames a key-ceremony code flaw and two similar-looking key labels. Browsers blocked the certificates within hours, but Go, Python, Node and curl need manual updates. eMudhra is exiting the global TLS business.

 Author:  @ Deepak Kandpal
Sat Oct 24 2026

🔑 eMudhra's "Private Keys" Were Just Tiny Numbers: What Happened and What to Do

A secret key that was just the number 4: eight eMudhra CA private keys, all smaller than 256, crackable in under a second

If you work anywhere near web security, your timeline has probably been full of one name this week: eMudhra. The headline was "private keys exposed", but the real story is stranger, and honestly a bit funnier (and scarier) than a normal leak.

I read through the Mozilla bug report, eMudhra's own statement, the Cloudflare write-up, and the coverage from BleepingComputer, CyberScoop, Help Net Security, CoinDesk, Endor Labs and others, so you don't have to. This post explains what actually broke, in plain words, and what you should check on your own machines and servers.

:: Enjoy the content☕ ::

Status as of 23 October 2026:

This is still developing. eMudhra has said its full root-cause report is coming, and Mozilla's questions to the company are still open. I'll point out where sources disagree.

First: Nothing Was "Stolen" 🕵️

When we hear "private key exposed", we picture a hacker breaking into a server and walking out with a file. That is not what happened here.

Security researcher Scott Helme put it best: "Normally when a CA key is compromised, someone stole it!" Here, the key was effectively public from the day the certificate was created, because anyone could work it out from the public certificate itself.

What is a private key, really?

A private key is just a number. Its whole security comes from one thing: that number being too big and too random to guess.

For the curve eMudhra used (P-384), a proper key is a random number of roughly 116 digits. Guessing it would take about 10¹¹⁵ tries. For comparison, there are around 10⁸⁰ atoms in the observable universe.

What researchers found instead was a number smaller than 256. One of them was literally the number 4.

Comparison of what a P-384 private key should look like (about 116 digits) versus what was found (a number below 256, such as 4)

Why It Matters:

If there are only 256 possible keys, you don't need a supercomputer. A laptop tries all of them in less than a second. Helme did exactly that. Mozilla later recovered the keys independently, without knowing the original reporter's method, and people reported getting an AI agent to do it from a single prompt.

Who Is eMudhra and What Exactly Was Affected? 🏢

eMudhra is an Indian company and one of India's licensed certificate authorities (CAs). It sells digital signatures, eSign, enterprise security, and, until now, TLS/SSL certificates that make the little padlock appear in your browser.

The problem sits in eight intermediate CA certificates:

pie title The 8 Compromised Intermediate CAs "TLS (websites)" : 6 "Code signing" : 2
Intermediate Purpose
EM DV TLS CA - G3B / G3C TLS, Domain Validated
EM OV TLS CA - G3B / G3C TLS, Organization Validated
EM EV TLS CA - G3B / G3C TLS, Extended Validation
EM OV CS CA - G3B / G3C Code signing (trusted by Microsoft)

Each key actually has two certificates: one issued by eMudhra's own root, and one cross-signed by Sectigo. That is 16 certificates in total, all chaining to roots trusted by Apple, Google, Microsoft and Mozilla.

A Quick Detour: How Certificate Trust Works 📜

Your browser doesn't know every website on earth. It only trusts a small list of root CAs. Roots sign intermediates, intermediates sign the certificates for actual websites.

flowchart TD A[Root CA - already inside your OS or browser] --> B[Intermediate CA] B --> C[example.com certificate] B --> D[yourbank.com certificate] C --> E[Browser says: trusted ✅] D --> E

The intermediate's private key is the thing that signs those website certificates. So whoever holds an intermediate's key can sign a certificate for any domain they like, and it will look perfectly valid.

Normal certificate chain versus the chain with the eMudhra weak keys, where an attacker can sign a forged yourbank.com certificate

Risk: An attacker sitting between you and a server (public Wi-Fi, a hostile network, a compromised router) could present a forged certificate and impersonate the server. They don't break the encryption; they pretend to be the real site.

How Did This Even Happen? 🔬

eMudhra's preliminary explanation (posted on Mozilla's Bugzilla, bug 2083449) goes like this.

On 30 April 2025 the company held a key generation ceremony, the formal procedure where the CA creates its most sensitive keys inside a hardware security module (HSM). It created 24 intermediate CAs.

This time there was an approved deviation from the normal procedure: an extra "wrap/unwrap" test, because the keys were meant to be exported. A flaw in the code made the HSM create a second, weaker key pair. Then a very human thing happened. The labels on the strong and weak keys looked similar, so the weak ones were picked by mistake to create the certificate requests.

Diagram of the April 2025 key ceremony: a code flaw creates a second weak key pair, similar labels cause it to be selected, the root signs it and Sectigo cross-signs it

Those requests went to eMudhra's root and to Sectigo for cross-signing. The weak keys ended up in browser trust lists, and nobody noticed for roughly 18 months, through two independent audit cycles, by eMudhra's own account.

Key Insight:

eMudhra says the HSMs (FIPS 140-2 Level 3) themselves were not at fault, only one procedural step. Mozilla and other researchers are still asking whether the weak key was really generated inside the HSM or imported from somewhere else. That question is unanswered right now.

The Timeline ⏱️

Incident timeline from the April 2025 key ceremony through discovery on 17 October 2026, revocation on 18 October, browser blocks, and eMudhra exiting the TLS business

The short version, all dates UTC:

  • 17 Oct: A researcher known as Wayne notices the weak EC keys while testing against CCADB (the Common CA Database). He signs a message, "We have a problem here - Wayne", with each of the eight keys as proof and emails Apple, Google, Microsoft, Mozilla and eMudhra. Chrome blocks the six TLS intermediates within about 100 minutes of the report. Mozilla finishes its block by 22:59.
  • 18 Oct: eMudhra revokes all eight, reason caCompromise.
  • 19 Oct: Sectigo revokes its cross-signs. Apple blocks.
  • 20 Oct: Microsoft blocks. Mozilla and Chrome go public.
  • 21–22 Oct: eMudhra announces it is leaving the global SSL/TLS business.
  • 27 Oct (expected): Chrome removes the affected root emSign ECC Root CA - G3 in Root Store v43.

eMudhra's chairman, V. Srinivasan, said the certificates were revoked within 14 hours of discovery, that no infrastructure was compromised and no data was breached, and that global TLS was only about 1% of revenue. He also cited rising compliance costs and free certificates from big providers. Reporting says the company's shares fell around 40% in the two days after disclosure, and Indian authorities have started an investigation.

So… Was Anyone Actually Attacked? 🤷

Nobody knows for sure, and that's the uncomfortable part. What we can say:

  • eMudhra says it knows of no evidence the weak keys were exploited before disclosure.
  • India's CERT-In reported no malicious use as of Wednesday.
  • Cloudflare's review found no active exploitation on its services.
  • But the keys were recoverable for about 17 months, and none of the parties can prove a negative.

There's one more clue, from Certificate Transparency (CT) logs. CT is a public record of certificates issued by CAs, and Chrome argues that because nothing from these six TLS CAs was in CT before the block, no forged certificate could have worked in a CT-enforcing browser. The first logged certificate from these CAs appeared on 19 Oct at 20:24 UTC, around 48 hours after Chrome's block.

After that, the logs filled up fast. The tracker at ctlogs.dev lists about 107,000 certificates from those CAs as of 23 Oct, and almost all of them are one name set:

pie title Certificates logged from the compromised TLS CAs (as of 23 Oct) "Names google.com (all dated 21 Oct)" : 105901 "Everything else" : 1280

I wouldn't read malice into that. Browsers reject them now, and the rest of the list includes obvious test names like .invalid domains and the researcher's own we-have-a-problem.com hosts. But it shows how trivial it became to mint certificates once the keys were known.

Security Note:

CT only protects clients that enforce it. Browsers do. Plenty of scripts, servers and CLI tools don't. That is where the real risk lives.

The Part Most People Will Miss: It's Not Just Browsers 💻

Browsers got fixed within hours because they get revocation data pushed to them. Plenty of other software never checks revocation at all. Helme's tests (via CoinDesk) found that curl, Python, Node, Go and Java all accepted a forged certificate for Stripe's API. So eMudhra and Sectigo revoking the intermediates doesn't help those clients. Only updating their trust store does.

Table showing browsers protected by revocation while Go, Python, Node.js, curl, Java, containers, bundled cert files and macOS curl need updates

sequenceDiagram participant C as Your script (Python / Node / Go) participant A as Attacker on the network participant S as Real server C->>A: Connect to api.example.com A-->>C: Forged certificate signed with the weak key Note over C: Does it check revocation or CT? C->>C: No, and the old CA bundle still trusts the chain C->>A: Sends API keys and data A->>S: Relays or reads everything

Who is exposed?

Where Why What to do
Servers and scripts using Go, Python, Node.js, curl, Java Own or OS trust bundle, no revocation check Update runtime and ca-certificates
Docker and containers Old image = old CA bundle Rebuild from a patched base and redeploy
Libraries with their own frozen PEM file OS updates never touch them Replace the bundle or point to a fresh one
macOS built-in /usr/bin/curl Bundle doesn't check revocation (per Dennis Jackson, Mozilla) Use a patched curl, for example via Homebrew
Systems verifying code signatures emSign Root CS CA - G3 is trusted for code signing Review separately

Endor Labs also warned about the sneaky ones: some HTTP client libraries ship their own certificate file, so even a fully patched OS can't save you. Dependency scanners usually miss these because they aren't versioned dependencies.

🛠️ What You Should Do Right Now

flowchart TD A[Start] --> B{Do you run servers, scripts or containers?} B -->|No, just browse| C[Update browser and OS] B -->|Yes| D[Update ca-certificates and runtimes] D --> E[Rebuild and redeploy container images] E --> F[Hunt for bundled cert files in libraries] F --> G[Test with the researcher's test hosts] G --> H{Connection fails with a cert error?} H -->|Yes| I[You are protected ✅] H -->|No, it connects| J[Still trusts the bad chain ❌ keep patching] C --> I

1. Test your own stack

The researcher behind the public disclosure runs a test site. Connect to it from the same environment your app actually runs in, not just from your laptop's browser:

curl -sS https://dv-g3b-emudhra.we-have-a-problem.com -o /dev/null
  • A certificate error means that client rejects the compromised chain. Good.
  • A successful connection means it still trusts it. Not good.

There is also a noct version of the test hosts whose certificates were never logged to CT, which tells you whether your client enforces Certificate Transparency.

2. Patch what's patchable

Versions that the trackers list as fixed (check the live tracker for your exact distro, since this list changes daily):

Component Fixed version
Go 1.27.3 / 1.26.10
Node.js 26.12.1 / 24.22.1 / 22.23.4
Python certifi 2026.10.19
Rust webpki-roots 1.0.10
Linux Updated ca-certificates (Ubuntu, Alpine, Fedora, Arch, Gentoo, RHEL 8/9/10 and others)

Heads Up:

Some packages were still pending when the articles I read were published (Debian, FreeBSD, Bun and Node.js in one report, RHEL 7 and Bottlerocket in another). Don't trust my table over the live tracker: emudhra.we-have-a-problem.com.

3. Don't "fix" certificate errors by turning verification off

Cloudflare said it plainly, and it bears repeating. If you start seeing new certificate errors after patching, do not switch off verification. That removes the exact protection the patch restores.

4. Look backwards if you handle sensitive traffic

Endor Labs suggests reviewing TLS inspection, proxy and endpoint logs for certificates issued by these eight intermediates, especially for clients that don't enforce CT and that send credentials. The keys were weak since April 2025.

⚠️ Where the Sources Disagree

News moves fast and a few details don't line up. These are the ones I noticed:

  • Who found it? Mozilla's bug report and BleepingComputer credit Wayne. Some outlets credit Mozilla's Dennis Jackson, who made the public disclosure on 20 Oct.
  • Revocation date. Mozilla's bug and eMudhra's own statement say 18 Oct. One outlet says 20 Oct. eMudhra's status page apparently had its own dates off by a day, and the Bugzilla thread asks them to correct it.
  • Apple's block. Several sources say 19 Oct. The researcher's page lists 22 Oct, which may refer to additional protections.
  • "How long is a normal key?" A couple of articles say 77–78 digits. That's the size for a 256-bit curve. For P-384 it is about 116 digits. Either way, "below 256" is absurdly small.
  • How many certificates need migrating? eMudhra estimates around 30,000 (about 97% via ACME). Chrome's CT analysis counts about 30,800 unexpired precertificates chaining to the G3 root, almost all from two InCommon subordinate CAs. eMudhra says the distrusted ECC root serves one customer ecosystem in the United States.

💭 My Take

A few things stand out to me.

  1. The human factor is the story. Not a nation-state, not a zero-day. A code flaw, two similar labels, and a ceremony that didn't catch it. Two audit cycles also didn't catch it.
  2. A key being "compromised" doesn't need a breach. Weak randomness is a quiet failure that passes every "is the key present?" check.
  3. Revocation is weaker than we pretend. Browsers handled this in hours. Anything outside a browser depended on a software update, and some of that software is hiding in container images and vendored cert files.
  4. Certificate Transparency saved a lot of skin. The fact that browsers require a certificate to be publicly logged is probably the main reason this wasn't a much worse week.

If you remember only one thing: patch your trust stores, rebuild your images, and test from the place your code really runs.

❤︎ Stay tuned for more exciting content !


📚 Sources