‹ zgba 中国吧
EN
Eight Bits of Trust: eMudhras CA keys cracked in milliseconds

Eight Bits of Trust: eMudhra’s CA keys cracked in milliseconds

Sponsored by:   Report URI - XSS can ride a passkey-authenticated session. See it in the browser.

One of eMudhra’s certificate authority private keys is the number 4.

Not a number that starts with 4, or the number 4 followed by a few hundred random digits, just, 4… Another one is 56, and another is 115. I know, because I recovered all of them from their public certificates on my laptop just now, and it took less than a second.

On Saturday 17th October a security researcher reported to Apple, Google, Microsoft, Mozilla and eMudhra that the private keys for eight eMudhra intermediate certificates were compromised. Chrome pushed a CRLSet update blocking them that evening and Mozilla blocked them in Firefox via OneCRL a few hours later. On Tuesday 20th, Mozilla announced it publicly and shipped an NSS update removing the eMudhra root, and Chrome confirmed the root is going in Chrome Root Store v43.

The eight intermediates are six TLS issuing CAs (DV, OV and EV, two generations each) and two code-signing CAs, all created in April 2025. Every one of them was also cross-signed by Sectigo’s AAA Certificate Services root in May 2025.

That’s the “what”, but it’s the “how” that’s the interesting part, and it was summed up in one line on the thread by Ian Carroll:

These are elliptic-curve keys on the P-384 curve. The private key is just a number, d. The public key, the thing that goes in the certificate for the world to see, is d × G, where G is a fixed point on the curve that everyone uses and ”×” means adding G to itself d times using the curve’s special arithmetic.

Going forwards is easy, but going backwards, from the public key to d, is considered to be impractical. That’s the entire security model, and it only holds if d is enormous. A P-384 private key should be a random 384-bit number, which gives you 2³⁸⁴ possibilities (or roughly 10¹¹⁵), so nobody is ever going to search that.

eMudhra’s keys look like this:

A P-384 private key should look like this:

That’s 47 bytes of zeros and then one byte, and all eight keys are like that. A single byte has 256 possible values, so the “search” is: compute 1 × G, 2 × G, 3 × G, and stop when it matches the certificate, which is at most 255 steps.

So the whole thing, every certificate those CAs could ever issue, every client that trusted them, rested on eight bits.

Mozilla attached the affected certificates to their announcement, so I pulled all 16 (8 keys, each used in two issued certificates: once by eMudhra and once by Sectigo) and brute-forced them. Every single one fell over instantly, the six TLS values, and the two code-signing keys are just as weak:

It’s interesting that nothing about these certificates looks wrong. A public key derived from d = 4 is a perfectly valid point on the curve, the encoding is fine, the curve is fine, every structural check passes. The only way to find out is to try.

Normally when a CA key is compromised, someone stole it! There’s a thief, there’s a moment it happened, and you can at least reason about who now has access to that key.

Here, nobody had to steal anything. The key was effectively public from the day the certificate existed. Anyone who looked at one of these certificates, at any point since April 2025, could have recovered the key in milliseconds on commodity hardware. That’s a 17 month window and there is no way to know whether someone did.

Chrome made the point that because Chrome enforces Certificate Transparency, and no TLS certificates chaining to these CAs ever showed up in CT, no forged certificate could have been trusted by default in Chrome. That’s true and it’s reassuring for browsers. CT detects mis-issuance though, it doesn’t prevent it, and a lot of software doesn’t check CT at all.

Mainstream and updated browsers are likely absolutely fine. Chrome and Firefox block the intermediates directly and both require CT, and Safari requires CT too.

Everything else is a different story, though. Most non-browser TLS clients (so basically everything else, with default settings), things like curl, Python, Node, Go, Java, git, package managers and every script and daemon you’ve got, do three things that matter here: they trust a CA bundle on disk, they don’t check revocation by default, and they don’t check CT. So the fact that eMudhra and Sectigo have revoked these intermediates doesn’t help them at all. This is something that I find often when talking about TLS and PKI, understanding just how massive the client ecosystem is can be overlooked. We often focus on this in training when we look at modern solutions for revocation like CRLite, which works wonders on the desktop browsers, but does nothing for any other TLS client. Consider what needs its root store updating now, and this is just the tip of the iceberg:

I tested this on my own machines using a local server and a certificate for api.stripe.com, a name that we can all likely agree is very high value. With default settings, curl said SSL certificate verify ok, Python completed the handshake, and Node said authorized: true. That was true on every Linux and macOS machine I tested. On Windows, CryptoAPI accepted the chain unless revocation checking was switched on, and even then only one of the two routes came back as revoked.

You can put any other hostname you want in that certificate and you have everything you need to intercept that device’s traffic, all you have to do is get on the network path.

It’s fortunate that the steps required here aren’t particularly complicated for the devices you can update, and the advice essentially boils down to ‘update them’. The problem is the devices you can’t update or update easily.

Eight bits. For 17 whole months, that’s all that stood between a huge amount of non-browser software and a forged certificate for any site blowing the security on all of your encrypted traffic.

MDSP thread: https://groups.google.com/a/mozilla.org/g/dev-security-policy/c/0R3XLJL6FuE/m/Kp1v6CPuAAAJ

Research announcement: https://emudhra.we-have-a-problem.com/

Update 20th Oct 2026 20:16 UTCShortly after publishing, Mozilla made their incident ticket public: https://bugzilla.mozilla.org/show_bug.cgi?id=2083449

eMudhra have given their account of what happened on that ticket. It seems there was a bug in the script used during the ceremony, a second, weak key pair was created on the HSM, and having similar names a human error lead to the wrong keys being used for the CSR. Nothing in the text of my article above has changed as a result of this new information. I can also confirm that a simple prompt in an AI agent allowed me to recover the private keys of the CA. Claude was able to recover the private keys with a single prompt.

Practical TLS and PKI Training (US TZ, Virtual) 16th - 19th November 2026

Black Hat EU (London, England) 9th - 10th December 2026

BSides London (London, England) 12th December 2026

NDC Security (Oslo, Norway) 15th - 18th February

Report URI Why No Passkeys? Crawler.Ninja DBSC.dev CSP.win CSP.fail CSP.academy HTTP Forever Security Headers Why No HTTPS? BMW M140i

CSP Cheat Sheet HSTS Cheat Sheet HTTPS Cheat Sheet Performance Cheat Sheet

9 Feb 2026 – 6 min read

22 Apr 2025 – 6 min read

15 Oct 2024 – 4 min read

A post called Passkeys are a trap. Do not use them. has been doing the rounds over the last few days, making it pretty high on Hacker News, and I&…

View original article