Eight intermediate CA certificates run by the Indian certificate authority eMudhra had private keys that were whole numbers below 256. On a P-384 curve that is not a weak key; it is a published one, because anyone holding the certificate can try all 255 values in milliseconds and forge certificates for any domain. Browsers blocked the intermediates within hours of the 17 October report, Mozilla has removed the root that signed them, emSign ECC Root CA - G3, Chrome removes it on 27 October, and on 22 October eMudhra said it will leave the global SSL/TLS business (Google, Mozilla bug 2083449, eMudhra).
This article shows why a small private scalar is fatal, with a script that recovers one; how a key ceremony produced the wrong keys; and what the distrust breaks. If you run a site with a certificate from this hierarchy (most were issued through InCommon to universities and research institutions), you need a new certificate before Chrome's update lands. If you run clients, you need to check the trust stores you ship.
| Keys exposed | 8 intermediates under emSign ECC Root CA - G3: six TLS, two code signing; P-384 private keys between 4 and 237 |
| Root removed | emSign ECC Root CA - G3: Mozilla on 20 October; Chrome Root Store on 27 October (expected) |
| Live certificates hit | About 30,800 unexpired precertificates chain to the root, nearly all from two InCommon subordinate CAs (Chrome's count, 21 October) |
| Fraudulent certificates seen | None in Certificate Transparency logs before the block, per Google |
| Cause given | A flawed script in an April 2025 key ceremony created a second, weak key pair that was used for the CSRs |
| Business outcome | eMudhra will exit the global SSL/TLS certificate business; revocation services continue until certificates expire or are replaced |
What happened to eMudhra's CA keys?
On Saturday 17 October a researcher sent Apple, Google, Microsoft, Mozilla and eMudhra proof of control of the private keys for eight eMudhra intermediates. Mozilla's Dennis Jackson recovered the keys independently and found the P-384 private scalars were all below 256 (bug 2083449). Google describes them as "generated with insufficient randomness" (Google).
Each key had been used in two certificates, one issued by eMudhra and a cross-certificate from Sectigo, so 16 certificates had to be revoked (Scott Helme). eMudhra revoked its eight on 18 October with reason caCompromise, and Sectigo finished revoking its cross-signed copies around 20 October. eMudhra says none of the eight keys issued an end-entity certificate, and that its systems were not breached (eMudhra).
Why a private key below 256 can be found in milliseconds
An elliptic-curve private key is a number d; the public key is the curve's fixed generator point G added to itself d times. Going forwards is cheap. Going backwards is the discrete logarithm problem, which is only hard because d is drawn from a space as large as the curve's order:
Every certificate carries Q. If d is below 256, an attacker computes 1·G, 2·G, 3·G and stops when the point matches, at most 255 steps. Helme reports the eight keys "fell over instantly" on a laptop (Scott Helme). The script below does the same against a key it builds itself with d = 4, the value recovered for EM OV TLS CA - G3C, using only the public point:
"""Why a P-384 private key below 256 is no key at all. Builds a key pair with d = 4 (the value Scott Helme recovered forEM OV TLS CA - G3C), then recovers d from the public key alone.Needs: pip install cryptography"""import time from cryptography.hazmat.primitives.asymmetric import ecfrom cryptography.hazmat.primitives.serialization import Encoding, PublicFormat def public_point(key): return key.public_key().public_bytes(Encoding.X962, PublicFormat.UncompressedPoint) def recover(target, limit=256): """Try d = 1, 2, 3 ... and compare d·G with the published point.""" for d in range(1, limit): if public_point(ec.derive_private_key(d, ec.SECP384R1())) == target: return d return None weak = ec.derive_private_key(4, ec.SECP384R1())start = time.perf_counter()d = recover(public_point(weak))print(f"weak key: d = {d} recovered in {(time.perf_counter() - start) * 1000:.1f} ms") strong = ec.generate_private_key(ec.SECP384R1())print(f"strong key: d has {strong.private_numbers().private_value.bit_length()} bits;", "recover() finds", recover(public_point(strong)))$ pip install cryptography$ python3 weak_p384.pyweak key: d = 4 recovered in 2.2 msstrong key: d has 382 bits; recover() finds NoneThe strong key's scalar happens to have 382 significant bits; a properly random one is close to 384, and no loop will reach it. With the weak key, the attacker holds the intermediate CA's signing key, and can sign a certificate for any domain that clients trusting the root will accept.
A certificate publishes its public key, so a key chosen from 255 values is published too.
| Intermediate | Use | d |
|---|---|---|
| EM DV TLS CA - G3B | TLS | 156 |
| EM DV TLS CA - G3C | TLS | 230 |
| EM EV TLS CA - G3B | TLS | 115 |
| EM EV TLS CA - G3C | TLS | 56 |
| EM OV TLS CA - G3B | TLS | 155 |
| EM OV TLS CA - G3C | TLS | 4 |
| EM OV CS CA - G3B | Code signing | 66 |
| EM OV CS CA - G3C | Code signing | 237 |
How a key ceremony produced the wrong keys
eMudhra's account, posted to the Mozilla bug, is that the keys came from a key generation ceremony on 30 April 2025 using Utimaco HSMs. An approved deviation to test key wrapping was added to the ceremony; a flaw in that code generated a second, weak key pair on the HSM; and because the key labels were similar, the weak pair was used for the certificate signing requests that the root signed and Sectigo cross-signed (bug 2083449).
- Key ceremony → HSM: script flaw
- HSM → Intended key
- HSM → Weak key
- Weak key → emSign ECC Root CA - G3: CSR
- Weak key → Sectigo: CSR
- emSign ECC Root CA - G3 → Browser trust stores
- Sectigo → Browser trust stores
- Weak key → 2025 CRLs
There was an earlier clue. In 2025 eMudhra published invalid CRLs for six of the same intermediates (bug 1970728). It has now told Mozilla those CRLs were first signed with the intended keys, failed verification, and were then "resigned with flawed keys". Chrome called this a serious transparency concern and asked, in a list of questions, why the 2025 report did not mention two key pairs per CA (The Hacker News).
The questions are not finished. Participants in the bug found that a CRL for emSign Root TLS CA - G1, the RSA hierarchy eMudhra is moving customers to, was signed with an OCSP certificate's key, not the CA's own. Others asked how a certified HSM's generator could produce such keys unnoticed; that was unanswered when this was written (bug 2083449).
What browsers and operating systems did
The intermediates were blocked fast, without users updating anything. The root removal is what breaks legitimate sites.
| When (UTC unless noted) | Who | Action |
|---|---|---|
| 17 Oct, 18:05 | Chrome Root Program | Receives the report (Google) |
| 17 Oct, 19:45 | Chrome | CRLSet update blocks the intermediates' SPKI hashes; no browser restart needed |
| 17–18 Oct | Firefox | Intermediates added to OneCRL (bug 2083449) |
| 19 Oct, ~22:00 | Android | Equivalent block through Google Play Services |
| 19–20 Oct | Apple, Microsoft | Block the certificates (CyberScoop) |
| 20 Oct | Mozilla, Ubuntu | Distrust of emSign ECC Root CA - G3; Ubuntu ca-certificates 20260816 removes it (USN-8944-1) |
| 27 Oct (PDT, expected) | Chrome | Removes emSign ECC Root CA - G3 from the Chrome Root Store |
Mozilla said on 20 October it was not removing trust in eMudhra's RSA root, emSign Root CA - G1. Chrome is still reviewing whether eMudhra's remaining roots stay in its store (Google, The Hacker News).
Is my site affected? Check the chain
Your site is affected if its certificate chains to emSign ECC Root CA - G3. In practice that means an ECC certificate from InCommon: Chrome counts about 30,791 of the roughly 30,800 unexpired certificates as issued by two InCommon subordinate CAs, after InCommon moved to eMudhra's CertiNext platform earlier this year (bug 2083449, The Hacker News). Look at the issuer names your server sends:
host=www.example.eduopenssl s_client -connect "$host:443" -servername "$host" -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ +i:'# Affected if any issuer (i:) line names an emSign ECC ... G3 CACheck every endpoint, not only the main site: load balancers, mail servers and internal services often carry their own certificates from the same account.
Replace the certificate now; don't wait for renewal
Google's instruction to operators is to "immediately acquire and install a new TLS certificate from another PKI hierarchy" in the Chrome Root Store (Google). About 97% of the affected certificates were issued via ACME, according to eMudhra, and that is the trap: a standard ACME client will not replace a certificate that is still outside its renewal window unless it supports ARI or someone forces it (The Hacker News).
ARI, ACME Renewal Information (RFC 9773), lets a CA tell clients to renew early. If your client does not support it, or you cannot confirm the CA has set the window, force a renewal and ask for RSA, which chains to the G1 root, or move to another CA entirely:
certbot renew --cert-name www.example.edu --force-renewal --key-type rsa# changing key type on an existing certificate may ask for confirmation; check your certbot version# or issue from a different CA altogether and repoint your server configClients: update the trust stores you forget
Browsers fixed themselves. Everything that carries its own CA bundle did not. Helme lists operating system ca-certificates, Python's certifi, Node.js, Homebrew and container base images; Go and several Linux distributions also shipped updates (Scott Helme, CyberScoop). On an updated Ubuntu 24.04 host with a current certifi, the root is gone:
$ dpkg-query -W ca-certificatesca-certificates 20260816ubuntu0.24.04.1$ ls /etc/ssl/certs | grep -ci emsign0$ python3 -c "import certifi; print(certifi.__version__)"2026.10.18$ grep -c 'emSign ECC Root CA - G3' "$(python3 -c 'import certifi; print(certifi.where())')"0Container images are where this lingers: an image built last month keeps last month's bundle until you rebuild it on an updated base. Devices that are hard to update, such as routers, printers and televisions, will trust the root until it expires in 2039, so Helme recommends turning on revocation checking where you can, for example on Windows, where CryptoAPI accepted the chain unless revocation checking was enabled.
What to do today
- To do: Inventory certificates issued through InCommon or eMudhra, and run the chain check on every endpoint.
- To do: Replace any certificate chaining to emSign ECC Root CA - G3 before 27 October; force renewal if your ACME client lacks ARI.
- To do: Decide whether RSA G1 or another CA is your next hierarchy, given Chrome's open review.
- To do: Update
ca-certificates,certifi, Node.js and other bundled stores, and rebuild container images on patched bases. - To do: If you rely on eMudhra code-signing certificates, check the status of the G3 code-signing intermediates with eMudhra.
Questions people ask about the eMudhra distrust
What happened to eMudhra?
Eight of its intermediate CA certificates had P-384 private keys below 256, which anyone could recover from the public certificate. Browsers blocked them, Mozilla and Chrome are removing the emSign ECC Root CA - G3 root, and eMudhra announced on 22 October 2026 that it is leaving the global SSL/TLS business.
Which root certificate is being distrusted?
emSign ECC Root CA - G3. Mozilla removed it on 20 October 2026 and Chrome's removal is expected on 27 October. Mozilla said it was not removing emSign Root CA - G1, the RSA root, though Chrome is still reviewing eMudhra's remaining roots.
Were any fraudulent certificates issued?
Google found no TLS certificates chaining to the affected intermediates in Certificate Transparency logs before the block, and eMudhra says none were issued. Whether anyone used the keys privately is not known.
Is my InCommon certificate affected?
If it is an ECC certificate that chains to emSign ECC Root CA - G3, yes. Nearly all of the roughly 30,800 affected certificates came from two InCommon subordinate CAs; check the issuer names your server sends.
Will my ACME client replace the certificate automatically?
Not necessarily. Standard ACME clients renew only inside their renewal window unless they support ARI (RFC 9773) and the CA signals early renewal, so force a renewal or reissue manually.
How were the keys cracked so fast?
An elliptic-curve public key is the private number times a fixed point. With the private number below 256, trying every value takes at most 255 multiplications, which runs in milliseconds.
Do I need to update anything on servers that only make outbound calls?
Yes, if they ship their own trust store. Update ca-certificates, certifi, Node.js and similar bundles, and rebuild container images, so they no longer trust the removed root.
Sources and further reading
- Google: Protecting Chrome and Android users from compromised eMudhra intermediate CA certificates
- Mozilla bug 2083449: eMudhra intermediate certificate key compromise and bug 1970728 (the 2025 CRL incident)
- Scott Helme: Eight bits of trust, eMudhra's CA keys cracked in milliseconds
- eMudhra: exit from the global SSL/TLS certificate business
- CERT-In advisory CIAD-2026-0050 and Ubuntu USN-8944-1
- RFC 9773: ACME Renewal Information
- Reporting: The Hacker News and CyberScoop
Discussion
Join the discussion
Sign in with Google, Apple or an email code to comment and reply.