Back
23/10/2026
On October 20, 2026, it became public that the private keys of eight intermediate certificate authorities (CAs) run by eMudhra, an Indian CA, can be recovered by anyone. Browsers blocked the certificates the same day the problem was reported. Many Java applications, however, still trust them today, and they will keep trusting them until someone updates the JDK or changes its truststore.
On October 21, 2026, BellSoft published test results showing that many Java runtimes still accept these certificates. This article summarises their findings, which we verified in our own tests, and explains why Java is affected when browsers are not, how to check your systems, and what to do about it.
Key takeaways
- Eight eMudhra intermediate CA keys are compromised. Anyone holding one can issue a certificate for any hostname, and a client that trusts the chain will accept it.
- Browsers block them, but Java uses its own truststore and by default checks neither revocation nor Certificate Transparency.
- JDK builds from several vendors still trust some or all of the affected chains, including in container images.
- Until your vendor ships a fixed JDK, remove the two affected roots from the truststore, after testing. Revocation checking is a second option.
What happened
eMudhra generated the private keys of eight of its intermediate CA certificates incorrectly, so anyone can recover them from the public certificates. That has been possible since the intermediates were issued in April 2025.
On October 17, 2026, a reporter proved the problem by signing the message “We have a problem here” with each of the eight keys and sending the signatures to the browser root programs. The details went public on October 20.
- Six intermediates issue TLS certificates: the eMudhra DV, OV and EV TLS CAs, generations G3B and G3C.
- Two intermediates issue code-signing certificates.
- Each intermediate exists twice: signed by an eMudhra emSign root, and cross-signed by Sectigo’s
AAA Certificate Servicesroot. In a JDK truststore, the chains end at one of two roots:emSign ECC Root CA - G3(through a cross-sign) orAAA Certificate Services.
Firefox and Chrome have blocked the intermediates since October 17, Apple since October 19 and Microsoft since October 20. eMudhra revoked all eight on October 18 and 19 with the reason CA_COMPROMISE. Linux distributions have released updated CA certificate packages.
What the impact is
Anyone who holds one of these keys can create a certificate for any hostname, such as your bank, your cloud provider or your own API gateway. A client that trusts the chain will accept it. Combined with a way to intercept traffic, for example a compromised network or a changed DNS record, an attacker could:
- read and change traffic between a Java application and the services it calls, including passwords, API keys and tokens;
- impersonate package repositories, update servers or partner APIs;
- through the two code-signing intermediates, sign code that appears to come from a trusted publisher.
The intermediates never appeared in Certificate Transparency (CT) logs, so browsers that enforce CT could not have been attacked through them. Whether the keys were used against clients that skip CT is not known yet. Java is one of those clients.
Why Java still trusts these certificates
Mozilla, Google, Apple and Microsoft pushed the block through their own channels, such as OneCRL, CRLite and CRLSets. The JDK’s default TLS implementation reads none of them. Three defaults keep Java exposed:
- Its own truststore. Unless an application sets
javax.net.ssl.trustStore, Java trusts the roots in$JAVA_HOME/lib/security/jssecacertsif that file exists, and in$JAVA_HOME/lib/security/cacertsotherwise. A vendor-bundledcacertsreceives no browser blocklists and no operating system CA updates. It changes only when an administrator edits it or a JDK update replaces it. - No revocation checking. Java does not check revocation unless you enable it (
com.sun.net.ssl.checkRevocationis false by default), so the CA’s revocation is invisible to a default configuration. - No Certificate Transparency. The JDK does not enforce CT, so the protection that covered browser users does not apply.
The disclosure page lists twelve test hosts, one for every intermediate and root combination. BellSoft tested them on Linux on October 21, and we repeated the test on October 23:
| Runtime tested | Test hosts trusted |
|---|---|
| Liberica JDK 21.0.10 | 12 of 12 |
| Liberica JDK 8u504 (container image) | 12 of 12 |
| Liberica JDK 21.0.12.1 (container image) | 12 of 12 |
| Eclipse Temurin 25.0.4.1 | 6 of 12 (eMudhra root only) |
| Eclipse Temurin 21.0.12.1 (container image, our test) | 6 of 12 (eMudhra root only) |
| Arch Linux OpenJDK 27 (system CA store) | 6 of 12 (eMudhra root only) |
The difference is the Sectigo root. Mozilla had already removed AAA Certificate Services, and the Temurin and Arch Linux truststores are built from the Mozilla list, so only the eMudhra path is open. The Liberica JDK truststore still contains that root, so both paths are open.
Which systems to check
- Standalone JDKs unpacked from a vendor archive or installed with a vendor installer. These use their own
cacerts. - Container images that ship a JDK. In the images BellSoft tested, updating the operating system’s
ca-certificatespackage did not change the JDK’scacerts. Pulling a newer base image did not help either: the tested Liberica image from October 21 still trusted all twelve test hosts. - Applications with their own truststore, set with
javax.net.ssl.trustStore, in an application server configuration, or inside the application. Check whether they contain the two roots. - Distribution-packaged OpenJDK. Check where
cacertspoints. If it links to the system CA store (on Arch Linux it is a symlink to/etc/ca-certificates/extracted/java-cacerts.jks), the distribution’sca-certificatesupdate fixes it. The disclosure page lists the patched package versions.
How to check your JDK
First, look for the two roots in the truststore. Alias names differ between vendors (Liberica JDK uses emsigneccrootcag3 [jdk], Temurin uses cn_emsign_ecc_root_ca__g3,...), so search by certificate subject. Several other emSign roots exist; only emSign ECC Root CA - G3 is affected. On JDK 9 and later:
keytool -list -v -cacerts -storepass changeit | grep -E '^Alias name:|^Owner:' | grep -B1 -E '^Owner: CN=(emSign ECC Root CA - G3|AAA Certificate Services),'
Java 8’s keytool has no -cacerts option, and its truststore lives under jre/:
keytool -list -v -keystore "$JAVA_HOME/jre/lib/security/cacerts" -storepass changeit | grep -E '^Alias name:|^Owner:' | grep -B1 -E '^Owner: CN=(emSign ECC Root CA - G3|AAA Certificate Services),'
Each match prints the alias name followed by the certificate subject. Note the alias names: you need them for the fix.
Then test real connections. This small program connects to all twelve test hosts and runs on Java 8 and every later release:
import java.net.URI;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLHandshakeException;
public class Check {
public static void main(String[] args) {
for (String level : new String[]{"dv", "ov", "ev"})
for (String gen : new String[]{"g3b", "g3c"})
for (String via : new String[]{"", "-aaa"}) {
String host = level + "-" + gen + via + "-emudhra.we-have-a-problem.com";
try {
HttpsURLConnection c = (HttpsURLConnection) URI.create("https://" + host).toURL().openConnection();
c.setConnectTimeout(10000);
c.setReadTimeout(10000);
c.connect();
c.disconnect();
System.out.println("TRUSTED " + host);
} catch (SSLHandshakeException e) {
System.out.println("TLS_REJECTED " + host);
} catch (Exception e) {
System.out.println("ERROR " + host + " (" + e + ")");
}
}
}
}
On JDK 11 or later, run it with java Check.java. On Java 8, or where only a JRE is installed, compile it first with javac Check.java (on a machine with a JDK if needed) and run java Check. A TRUSTED line means this JDK accepts a compromised intermediate. ERROR means the host could not be reached, which proves nothing either way. Run the check with the same JDK and truststore settings as your application, including inside your containers.
How to fix it
1. Remove the two roots (recommended until a fixed JDK ships)
These are the same two roots that the disclosure page tells Linux and macOS users to distrust. Run the commands as the user who owns the JDK, with the alias names you found in the check. For example, on Liberica JDK:
keytool -delete -cacerts -storepass changeit -alias "comodoaaaca [jdk]"
keytool -delete -cacerts -storepass changeit -alias "emsigneccrootcag3 [jdk]"
On Java 8, replace -cacerts with -keystore "$JAVA_HOME/jre/lib/security/cacerts". If your truststore contains only one of the two roots, as Temurin’s does, delete only that one.
If you cannot modify the JDK installation, edit a copy and point the JVM at it:
cp "$JAVA_HOME/lib/security/cacerts" ./trimmed-cacerts
keytool -delete -keystore ./trimmed-cacerts -storepass changeit -alias "comodoaaaca [jdk]"
keytool -delete -keystore ./trimmed-cacerts -storepass changeit -alias "emsigneccrootcag3 [jdk]"
java -Djavax.net.ssl.trustStore=./trimmed-cacerts -Djavax.net.ssl.trustStorePassword=changeit -jar app.jar
In our tests, both methods made Liberica JDK 8 and 21 reject all twelve test hosts, while ordinary sites such as sectigo.com and github.com still connected.
For container images, delete the roots at build time so every new image is fixed:
FROM bellsoft/liberica-runtime-container:jdk-21-musl
RUN keytool -delete -cacerts -storepass changeit -alias "comodoaaaca [jdk]" \
&& keytool -delete -cacerts -storepass changeit -alias "emsigneccrootcag3 [jdk]"
Distroless and non-root images need two changes: they have no shell, so use the exec form of RUN with one command per line, and they run as an unprivileged user, so switch to USER root for the edit and back to the image’s normal user afterwards.
Tip: Removing a root is broader than blocking eight intermediates. A legitimate server whose chain ends only at one of these roots will stop working. Test the services your application calls before you roll this out, and run the check again after every JDK update, because an update or reinstall can restore the original cacerts.
2. Turn on revocation checking (optional)
eMudhra has revoked all eight intermediates, so a JVM that checks revocation rejects them without any change to the truststore. Enable CRL distribution points and OCSP:
echo 'ocsp.enable=true' > revocation.security
java -Dcom.sun.net.ssl.checkRevocation=true \
-Dcom.sun.security.enableCRLDP=true \
-Djava.security.properties=revocation.security \
-jar app.jar
In our tests this rejected all twelve test hosts on Liberica JDK 8 and 21 and on Temurin 21. It changes how every certificate is validated, though. The JVM makes OCSP or CRL lookups during path validation, and a handshake can fail when the revocation status cannot be determined. Before you enable it globally, test whether the responders are reachable from your servers, how much latency they add, and how failures behave. Use it if you already run with revocation checking, or alongside the root removal.
3. Update the JDK when fixed builds are available
BellSoft has said it is preparing Liberica JDK updates that remove these roots. Watch your own JDK vendor’s security advisories. When the update ships, read its release notes to confirm that it covers the eMudhra certificates, install it, rebuild your container images, and run the check again. A newer version number alone is not proof.
After the fix: review your exposure
The keys could be recovered for about eighteen months, so the fix closes the door but does not tell you whether anyone used it. For systems that send credentials or sensitive data, search TLS inspection, proxy and endpoint logs for certificates issued by the eight eMudhra intermediates. If you find anything suspicious, rotate the affected credentials.
In the longer term, treat truststores like dependencies: know where each one is, who updates it, and how quickly a change reaches production. This incident shows that a browser update is not enough when your servers run their own copy of the trust list.
Need help? LOGIQ provides support for OpenJDK and Linux, including security patching. If you want help finding every JDK and truststore in your environment or rolling out a fix safely, contact us.
Further reading
- eMudhra Intermediate CA Compromise: the disclosure page, with test hosts and patched package versions
- BellSoft: Distrusting compromised eMudhra intermediates in Java
Japan
Korea
China
Taiwan
Vietnam
Thailand
Indonesia
Portugal
Spain
France
Germany
Egypt
Russia