Blog

The eMudhra CA Compromise, just another cautionary tale


Abhijith B R Founder and Director

Here is my take on the eMudhra incident

A lot of what keeps you safe depends on companies you have never audited and you cannot see. The eMudhra incident is the cleanest example which we have seen and this failure is almost insultingly simple and this is much bigger than one Indian certificate authority having a bad week.

On October 17, 2026, Mozilla got a report that eight intermediate certificate authority (CA) certificates from eMudhra, under its globally trusted emSign brand, contained elliptic-curve public keys so weak that the matching private keys were very small numbers. One of them was literally 4. Six of the eight are TLS issuing CAs chaining to emSign ECC Root CA - G3, a root authority trusted by Chrome and Apple, and by Mozilla until it removed the root from NSS on October 20. The other two are code-signing CAs under emSign Root CS CA - G3, a root trusted by Microsoft. For roughly eighteen month anyone who thought to check, and could count to 256 could have held a key the internet would accept as a trusted certificate authority. Once the weakness was reported the browsers revoked within hours.

Nobody appears to have exploited it the response from the root programs was pretty fast and genuinely good, and if you only use a modern browser you were good the whole time. But "being good" is doing a lot of work in that sentence and the people it quietly leaves out are exactly the ones who will read about this on a news site, assume it does not apply to them and move on.
This post is just my attempt to be precise about what broke what it actually touches, how you can check your own exposure in a few minutes, and what I think the organizations that depend on certificates should change because of it.

eMudhra's April 2025 key produced a second set of broken ECDSA P-384 key pairs whose private keys were tiny integers, and those broken public keys ended up in eight intermediate CA certificates signed by the root. Because an ECDSA public key is Q = dG, recovering the private key d from a public certificate takes nothing more than counting up from 1 until dG matches Q. The researcher Scott Helme says he pulled all eight out of the public certificates in under a second.

What was actually broken?

When the news broke out that the eMudhra's keys were compromised most people pictured some sophisticated attack, but it was not. The keys were simply weak; almost unbelievably weak. Note that these are ECDSA keys on the P-384 curve.

Every certificate is built on a key pair with two matching halves: a public key, which goes inside the certificate for the world to see, and a private key, which is meant to stay secret forever. That private key is a gigantic, random number. The long blocks of letters and numbers you may have seen in key files are that number written in text form (base64), packaged with a little extra information such as which curve it belongs to. The entire security of the system rests on one assumption that the number is so large and so random that nobody could ever guess it..

cracking the key by counting to four

eMudhra's secret keys were very guessable. These are the actual private keys behind the eight broken certificate authorities, exactly as the researcher Scott Helme published them.

The eight private keys:

4, 56, 66, 115, 155, 156, 230, 237

One of the most trusted private keys on the internet was the number 4. The largest of the eight was 237.

So how do you "crack" a secret that might be a tiny number? You do not bother cracking it, you just try them in order. Is it 1? Is it 2? 3? 4? Each guess takes a sliver of a second, and you test it against the public half the CA already handed out. For a key like 4, you have your answer almost before you have started.

You can do exactly the same in about ten lines of code. Pull the public key out of each of the eight certificates, then count upward and ask one question each time. Does this guess produce that public key?

Terminal output from a key-recovery script run against the published eMudhra intermediate certificates. For each certificate it prints the issuer and a result line reading COMPROMISED with the recovered private key, for example d = 156, d = 230, d = 115 and d = 56, each found in about one millisecond.

I have executed the recovery against the published certificates in lab environment. Each private key falls out in about a millisecond.

That is the entire attack. No supercomputer, no GPU farm, no stolen hardware. You read the public key the CA published on purpose and you count up from one. And because it is the public certificate that gives the secret away, there is no taking it back: anyone can re-derive these keys, forever, from information that is designed to be shared. You cannot un-publish a certificate. The only real fix is to stop trusting it.

The emSign root certificate, trusted by every major browser, signs 8 eMudhra CA certificates.

CA keys are supposed to be born inside a Hardware Security Module (HSM) and never leave it. The whole point of that practice is that certified hardware with a real key generator produces the key under proper control with an audit trail. On April 30, 2025 eMudhra created such keys and it went wrong in a way nobody caught for a year and a half.

  • A P-384 private key of the value 4 is not something a certified HSM's random number generator produces by accident. Mozilla found that every one of the eight keys was zero in all but the last of its 48 bytes, which is why all eight are below 256. eMudhra blames its ceremony script, not the HSM hardware.
  • Nobody checked the key before it was trusted, the broken public keys through CSR creation, intermediate issuance, root signing, and disclosure to the root programs, and not one step asked the obvious question.

In late May 2025, CRLs for six TLS intermediates started failing signature validation because eMudhra's pipeline signed them with the original strong private keys while the public certificates carried the weak ones. Sectigo reported the mismatch on June 3; eMudhra's spam filter blocked the email until June 6. The CRLs were re-signed the ticket (Mozilla Bug 1970728) was closed as a process error and no one asked why the public keys did not match the keys on the HSM. That mismatch was the issue itself in plain sight sixteen months before anyone named it.

How it came to light and how the browsers responded

On Saturday, October 17, 2026, a researcher reported to Apple, Google, Microsoft, Mozilla and eMudhra that the eight intermediates' private keys were easily recoverable, and Mozilla's bug notes that it recovered them independently to confirm. Scott Helme published his write-up, Eight Bits of Trust, the same weekend, having pulled all eight keys off the public certificates on his laptop in well under a second. The browser response over the next three days is the reason this stayed as harmful as it could have.

The authoritative public record is Mozilla Bugzilla 2083449, and it is good to read the full thing rather than just the headline. Roughly 30,000 certificates chaining to emSign ECC Root CA - G3 through its other intermediates need to migrate off that root (eMudhra pointed customers to its RSA root, emSign Root CA - G1), about 97% issued through ACME. They have to move because the root is being removed, not because their own keys were weak. Out of the eight intermediates, only one was ever deployed in production, eMudhra says none had issued an end-entity certificate and nothing chaining through the six TLS CAs was ever found in Certificate Transparency.

The eight compromised intermediates

Six are TLS issuing CAs (domain-validated, organization-validated and extended-validation, in two generations G3B and G3C) chaining to emSign ECC Root CA - G3. Two are organization-validated code-signing CAs. The fingerprints and serials came from Mozilla's incident bug (Bugzilla 2083449) and CCADB.

Who is actually affected and at what level

This is the question most of the news about it bad at answering. "A certificate authority was compromised" is technically true and practically useless, because the exposure is wildly different depending on which side of the certificate you sit on.

Who all are affected?

By certificate type

Three TLS validation tiers are hit (DV, OV and EV) across two generations, plus organization-validated code signing. Your own certificate almost certainly does not chain through one of the eight, because eMudhra says none of them issued an end-entity certificate. But if you bought an ECC TLS certificate from eMudhra or an emSign reseller, it very likely chains to the same G3 root, and that root is being removed. eMudhra put the number at roughly 30,000 certificates needing migration, about 97% issued through ACME, which at least makes re-issuance scriptable.

By software

Browsers kind of fixed themselves. Language runtimes and tools ship their own trust stores and frequently do not check revocation at all: Go has shipped an emergency update, and Node.js, Java, Python, curl and OpenSSL bundles, and container base images are on their own schedules. Appliances, IoT and anything air-gapped or slow to update stays exposed the longest. On the code-signing side, there is no Certificate Transparency to fall back on, so the usual "nothing showed up in the logs" reassurance simply does not exist.

By person

If you are an individual who just reads the news and browses, you did not need to do anything. If you host a website, ship software, or operate backend services, this is certainly your problem, and the smaller your team the more likely it is that nobody is watching the trust-store updates for you.

The real impact and risk

What someone holding these keys could do is serious. With a TLS issuing CA key you can sign a leaf certificate for any domain, your bank, an update server, anything and any client that trusts the root will accept it. Put that together with a network position asuch as public Wi-Fi, a compromised router, a cooperative ISP, DNS tampering and you have a clean machine-in-the-middle against TLS with no warning. With the code-signing key, you can produce trusted-signed malware.

How to test whether you are affected

There are two separate questions, and they need different tests. First: does anything I serve or trust chain through one of the eight bad intermediates? Second, and more fundamental: is a key I am looking at one of the weak keys? That second test needs no blocklist at all, which I find genuinely satisfying, so I will give you both.

1. Pull the chain your server serves and fingerprint every CA in it

Match on the SHA-256 of the certificate, not the subject name. Names can be reused or look alike across generations; the fingerprint is the certificate.

Compare each SHA-256 against the fingerprints in the table, ignoring case (openssl prints lower-case hex, the table is upper-case). A match means you are serving a chain built on a compromised intermediate and that leaf has to be re-issued, which, given that none of the eight issued end-entity certificates, should never happen for a legitimate item.

2. Test a public key directly for the weakness, no blocklist required

Take any certificate's EC public key Q and check whether it equals dG for a small d. If it does, the key is broken, whether or not it is on anyone's list yet. This is exactly the check eMudhra's own pipeline should have run before trusting those keys.

Extract the key with openssl x509 -in cert.pem -noout -pubkey > pub.pem, then python3 weak_ec.py pub.pem. (I'll uplaod teh code samples to GitHub) Run it against the emSign intermediates and it prints the private scalar. Better, point it at your own CA and issuance pipeline and leave it there: it is a standing check that no EC key you generate or trust has a private key below 65,536 (raise max_d if you want a wider net). It only handles EC keys; an RSA key will make it fail.

3. Enumerate what the bad intermediates ever issued, via Certificate Transparency

Browsers require publicly trusted TLS certificates to be logged, so CT is also your retroactive audit trail. Look up each compromised intermediate on crt.sh (search by its SHA-256, open its CA page, review what it issued), and run a CT monitor on your own domains. Under the eight intermediates you should find nothing, which is the confidence you want that no rogue leaf was ever logged. For the inventory of your own legitimate certificates that need re-issuing, search your domains for certificates chaining to emSign ECC Root CA - G3 instead.

I wanted to make a quick PoC

I wanted to see for myself how hard the forgery actually was and spun up a quick proof of concept and recreated it end to end. It was pretty damn easy. Created a certificate myself, for a hostname I do not own, chaining to the real emSign root. Scott Helme's write-up and the Bugzilla thread walk through the same extraction and forgery in detail.

The part that makes it so cheap: you do not forge the intermediate. I recovered the intermediate's private key from its published public key, downloaded the real intermediate certificate from crt.sh so the chain up to the root is genuine and then signed as many fresh leaf certificates.

Forging with the recovered d = 4 key under the genuine EM OV TLS CA - G3C intermediate.

cat leaf.pem em_intermediate.pem > chain.pem

# verify the forged leaf exactly as a client would, against the genuine root
openssl verify -CAfile emsign_root.pem -untrusted em_intermediate.pem leaf.pem
# -> leaf.pem: OK        the whole point, on one line

Openssl verifies the forged leaf against the genuine emSign root and prints 'forged_leaf.pem: OK'.

The same result, the forged leaf chains validly to the real root through the recovered intermediate key, so any TLS client trusting that root would accept the connection.

Auto updating browser program will not show a padlock for this. Chrome, Firefox, Safari and Edge now carry these intermediates on their blocklists, and they also require Certificate Transparency proof that a forged leaf never has.

# mapping the test name to this host in /etc/hosts, then serve leaf + intermediate
openssl s_server -accept 8443 -www \
    -cert leaf.pem -cert_chain em_intermediate.pem -key leaf_key.pem

# a client that trusts the emSign root and skips revocation and CT accepts it
curl --cacert emsign_root.pem https://test.example:8443/  

A browser padlock on a hostname the operator does not own, where the emSign root is trusted by hand. Firefox reports the connection as verified by eMudhra Inc. A manually trusted root is exempt from CT, which is why the forgery is accepted here.

The forged leaf's full chain in the certificate viewer, from the lab hostname up through the genuine EM OV TLS CA - G3C intermediate to the emSign roots.

Finding every sites that still uses these certificates

Checking your own chain is step one. The more useful question is the whole population, and it has two halves. First, did anything ever get issued under the eight intermediates? (It should not have: eMudhra says none issued an end-entity certificate, so any hit is a red flag.) Second, which sites still serve certificates from the wider emSign ECC G3 hierarchy that is losing trust? Three public sources answer these from different angles, and you want all three, because none is complete on its own.

SourceWhat you queryWhat it returns
crt.sh?sha256=<fingerprint> -> CA profile -> ?Identity=%25&iCAID=<CA id>Every certificate ever logged under an intermediate. Run it on the eight (expect nothing) and on the root's other intermediates (the re-issue list).
Shodanssl.cert.issuer.cn:"EM OV TLS CA - G3C"Hosts on the live internet serving a certificate from that issuer right now.
Censysservices.tls.certificates.leaf_data.issuer.common_name:"EM OV TLS CA - G3C"The same live view from a second scanner, useful to cross-check Shodan.

crt.sh: everything ever issued

Certificate Transparency is the complete, public, historical record of trusted TLS certificates, and crt.sh is the possible way in. The reliable way to list what one intermediate issued is by its crt.sh CA id, not by name. Look the intermediate up by its SHA-256 fingerprint (they are in the table above), open its CA profile, and read what it issued:

# 1. find the exact intermediate by its SHA-256 fingerprint
https://crt.sh/?sha256=CB6E15165AC802E9B3F993F16C25D41F4E81C21EBDE71AE1B012AC00BF9C7C3F

# 2. open its CA profile; the CA id is in the URL (crt.sh/?caid=NNN)
https://crt.sh/?caid=<CA id>

# 3. list every cert that CA issued (append &output=json to script it)
https://crt.sh/?Identity=%25&iCAID=<CA id>

Looking up one compromised intermediate on crt.sh by its SHA-256 fingerprint.

crt.sh gives you the authoritative "what needs reissuing" inventory for anything publicly trusted. What it cannot tell you is whether a given host is still online or still serving that certificate today.

Shodan and Censys

Shodan and Censys scan the live internet and index the certificate each host currently presents, which answers the "still exposed today" question CT cannot. Filter on the issuer common name: one of the eight names to hunt for anything rogue, or the names of the root's other G3 intermediates (read them off the root's crt.sh CA page) to find sites that still need migrating. Copy the CN exactly as crt.sh shows it, and expect certificate-field filters to need an account or a paid plan. Censys has also moved to its newer Platform, so confirm the current field path there:

# Shodan - live hosts serving a cert issued by a compromised intermediate.
# Use the issuer CN exactly as crt.sh shows it; these cert filters need a paid plan.
ssl.cert.issuer.cn:"EM OV TLS CA - G3C"
ssl.cert.issuer.cn:"EM DV TLS CA - G3B" ssl.cert.expired:false

# see where they are, by country and exact issuer
shodan stats --facets ssl.cert.issuer.cn,country \
    'ssl.cert.issuer.cn:"EM OV TLS CA - G3C"'
# Censys hosts (search.censys.io) - live hosts serving an affected cert
services.tls.certificates.leaf_data.issuer.common_name: "EM OV TLS CA - G3C"

# Censys certificates index - every matching cert, whether or not it is live
parsed.issuer.common_name: "EM OV TLS CA - G3C"

# on the newer Censys Platform the operator is = , not :
host.services.tls.certificates.leaf_data.issuer.common_name = "EM OV TLS CA - G3C"

Run each common name, or broaden to the shared prefixes (EM DV TLS CA, EM OV TLS CA, EM EV TLS CA, EM OV CS CA). Shodan and Censys only see what they have scanned, and only the current certificate, so treat them as "who is still visibly exposed," and treat crt.sh as "everything that was ever issued."

If you are an organization that just needs certificates, read this part

Most organizations are not certificate authorities, they are customers of them, and the entire incident is a reminder that you are trusting a vendor's competence with no way to verify it up front. You cannot audit eMudhra's key ceremony.

  • If you can re-issue every certificate with a config change, this is a non-event. The 97% of eMudhra certs on ACME are the easy ones to migrate; a once-a-year vendor portal is the first thing to fix.
  • Certificates that live for days keep your automation running constantly, so a forced migration is just one more cycle, and a stolen or forged cert is worth less.
  • A second ACME account ready, automation parameterized by issuer, no code assuming one intermediate forever. The issue you are avoiding is "our CA got distrusted and we have no plan B."
  • CAA will not stop a stolen key, but it is the cheapest control that keeps every rule-following CA from mis-issuing for your names.
  • Monitor Certificate Transparency for your own domains. A CT monitor flags the moment a certificate you did not request appears for you.
  • The residual risk is all about clients that do not update. Make sure every non-browser TLS client and signed dependency has an owner who can push a trust-store update within a day.
  • WebPKI is a supply chain, only as strong as its least careful supplier. Treat a CA distrust event as when it happened and practice it.

What I think we should learn from this

First, credit where it is due. Google and Mozilla within hours, Apple and Microsoft within days. Certificate Transparency did what exactly it was built to do. The browsers caught a potentially catastrophic failure and contained it over a weekend.

Second; All of this, eight CAs, an emergency root removal, 30,000 certificates to migrate, traces back to nobody running a one-line check that a freshly generated public key is not the product of a trivially small private key. CAs generate keys for a living. Proving those keys are sane before they are trusted should not be optional, and root programs are within their rights to require it.

The browser ecosystem is genuinely good at fast, coordinated distrust. Code signing, embedded devices, appliances, and the pile of non-browser TLS clients are not, and that is where incidents like this keep their value long after the news cycle ends.

Finally, treat this as a mock drill for a potential incident. A counting loop that any researcher could write reduced eight certificate authorities to nothing, and the whole industry had to yank trust fast. That is a small, low-stakes rehearsal for the day a cryptographic primitive actually breaks at scale and we have to do the same thing under real pressure.

Update: eMudhra is leaving the global TLS business

On October 22, 2026, days after the browsers blocked its keys, eMudhra announced it is stepping out of public TLS altogether rather than trying to rebuild trust in that business:

"eMudhra Limited (BSE: 543533 | NSE: EMUDHRA), a global digital trust company, today announced that its Board has decided to voluntarily withdraw from the global SSL/TLS certificate business."

- eMudhra press release, 22 October 2026

eMudhra's October 22, 2026 press release announcing its exit from the global SSL/TLS certificate business. Captured from emudhra.com.

References