Volver
2026/10/23
El 20 de octubre de 2026 se hizo público que cualquiera puede recuperar las claves privadas de ocho autoridades de certificación (CA) intermedias operadas por eMudhra, una CA india. Los navegadores bloquearon los certificados el mismo día en que se notificó el problema. Sin embargo, muchas aplicaciones Java siguen confiando en ellos hoy, y seguirán haciéndolo hasta que alguien actualice el JDK o modifique su truststore.
El 21 de octubre de 2026, BellSoft publicó resultados de pruebas que muestran que muchos runtimes de Java todavía aceptan estos certificados. Este artículo resume sus conclusiones, que hemos verificado en nuestras propias pruebas, y explica por qué Java está afectado cuando los navegadores no lo están, cómo revisar sus sistemas y qué hacer al respecto.
Puntos clave
- Ocho claves de CA intermedias de eMudhra están comprometidas. Quien tenga una puede emitir un certificado para cualquier nombre de host, y un cliente que confíe en la cadena lo aceptará.
- Los navegadores las bloquean, pero Java usa su propio truststore y, por defecto, no comprueba ni la revocación ni Certificate Transparency.
- Builds del JDK de varios proveedores siguen confiando en algunas o todas las cadenas afectadas, también en imágenes de contenedor.
- Hasta que su proveedor publique un JDK corregido, elimine las dos raíces afectadas del truststore, después de probarlo. La comprobación de revocación es una segunda opción.
Qué ha pasado
eMudhra generó de forma incorrecta las claves privadas de ocho de sus certificados de CA intermedia, de modo que cualquiera puede recuperarlas a partir de los certificados públicos. Esto es posible desde que se emitieron las intermedias, en abril de 2025.
El 17 de octubre de 2026, una persona que notificó el problema lo demostró firmando el mensaje “We have a problem here” con cada una de las ocho claves y enviando las firmas a los programas de raíces de los navegadores. Los detalles se hicieron públicos el 20 de octubre.
- Seis intermedias emiten certificados TLS: las CA TLS DV, OV y EV de eMudhra, generaciones G3B y G3C.
- Dos intermedias emiten certificados de firma de código.
- Cada intermedia existe dos veces: firmada por una raíz emSign de eMudhra y con firma cruzada de la raíz
AAA Certificate Servicesde Sectigo. En un truststore del JDK, las cadenas terminan en una de dos raíces:emSign ECC Root CA - G3(a través de una firma cruzada) oAAA Certificate Services.
Firefox y Chrome bloquean las intermedias desde el 17 de octubre, Apple desde el 19 de octubre y Microsoft desde el 20 de octubre. eMudhra revocó las ocho el 18 y el 19 de octubre con el motivo CA_COMPROMISE. Las distribuciones Linux han publicado paquetes de certificados de CA actualizados.
Cuál es el impacto
Quien tenga una de estas claves puede crear un certificado para cualquier nombre de host, como el de su banco, su proveedor de nube o su propio API gateway. Un cliente que confíe en la cadena lo aceptará. Si además dispone de una forma de interceptar el tráfico, por ejemplo una red comprometida o un registro DNS modificado, un atacante podría:
- leer y modificar el tráfico entre una aplicación Java y los servicios a los que llama, incluidas contraseñas, claves de API y tokens;
- suplantar repositorios de paquetes, servidores de actualizaciones o API de socios;
- mediante las dos intermedias de firma de código, firmar código que parezca proceder de un editor de confianza.
Las intermedias nunca aparecieron en los registros de Certificate Transparency (CT), así que los navegadores que exigen CT no podían ser atacados a través de ellas. Todavía no se sabe si las claves se usaron contra clientes que no comprueban CT. Java es uno de esos clientes.
Por qué Java sigue confiando en estos certificados
Mozilla, Google, Apple y Microsoft distribuyeron el bloqueo por sus propios canales, como OneCRL, CRLite y CRLSets. La implementación TLS predeterminada del JDK no lee ninguno de ellos. Tres valores predeterminados mantienen expuesto a Java:
- Su propio truststore. Salvo que una aplicación defina
javax.net.ssl.trustStore, Java confía en las raíces de$JAVA_HOME/lib/security/jssecacertssi ese archivo existe y, si no, en las de$JAVA_HOME/lib/security/cacerts. Uncacertsincluido por el proveedor no recibe las listas de bloqueo de los navegadores ni las actualizaciones de CA del sistema operativo. Solo cambia cuando un administrador lo edita o una actualización del JDK lo sustituye. - Sin comprobación de revocación. Java no comprueba la revocación a menos que usted la active (
com.sun.net.ssl.checkRevocationes false por defecto), por lo que la revocación hecha por la CA es invisible para una configuración predeterminada. - Sin Certificate Transparency. El JDK no exige CT, así que la protección que cubría a los usuarios de navegadores no se aplica.
La página de divulgación enumera doce hosts de prueba, uno por cada combinación de intermedia y raíz. BellSoft los probó en Linux el 21 de octubre, y nosotros repetimos la prueba el 23 de octubre:
| Runtime probado | Hosts de prueba aceptados |
|---|---|
| Liberica JDK 21.0.10 | 12 de 12 |
| Liberica JDK 8u504 (imagen de contenedor) | 12 de 12 |
| Liberica JDK 21.0.12.1 (imagen de contenedor) | 12 de 12 |
| Eclipse Temurin 25.0.4.1 | 6 de 12 (solo raíz de eMudhra) |
| Eclipse Temurin 21.0.12.1 (imagen de contenedor, nuestra prueba) | 6 de 12 (solo raíz de eMudhra) |
| Arch Linux OpenJDK 27 (almacén de CA del sistema) | 6 de 12 (solo raíz de eMudhra) |
La diferencia está en la raíz de Sectigo. Mozilla ya había retirado AAA Certificate Services, y los truststores de Temurin y Arch Linux se generan a partir de la lista de Mozilla, así que solo queda abierta la ruta de eMudhra. El truststore de Liberica JDK todavía contiene esa raíz, así que ambas rutas están abiertas.
Qué sistemas revisar
- JDK independientes descomprimidos de un archivo del proveedor o instalados con un instalador del proveedor. Usan su propio
cacerts. - Imágenes de contenedor que incluyen un JDK. En las imágenes que probó BellSoft, actualizar el paquete
ca-certificatesdel sistema operativo no cambió elcacertsdel JDK. Descargar una imagen base más reciente tampoco ayudó: la imagen de Liberica del 21 de octubre que se probó seguía confiando en los doce hosts de prueba. - Aplicaciones con su propio truststore, definido con
javax.net.ssl.trustStore, en la configuración de un servidor de aplicaciones o dentro de la propia aplicación. Compruebe si contienen las dos raíces. - OpenJDK empaquetado por la distribución. Compruebe adónde apunta
cacerts. Si enlaza al almacén de CA del sistema (en Arch Linux es un enlace simbólico a/etc/ca-certificates/extracted/java-cacerts.jks), la actualización deca-certificatesde la distribución lo corrige. La página de divulgación indica las versiones de paquete corregidas.
Cómo revisar su JDK
Primero, busque las dos raíces en el truststore. Los nombres de alias varían entre proveedores (Liberica JDK usa emsigneccrootcag3 [jdk], Temurin usa cn_emsign_ecc_root_ca__g3,...), así que busque por el sujeto del certificado. Existen otras raíces emSign; solo emSign ECC Root CA - G3 está afectada. En JDK 9 y posteriores:
keytool -list -v -cacerts -storepass changeit | grep -E '^Alias name:|^Owner:' | grep -B1 -E '^Owner: CN=(emSign ECC Root CA - G3|AAA Certificate Services),'
El keytool de Java 8 no tiene la opción -cacerts, y su truststore está en 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),'
Cada coincidencia muestra el nombre de alias seguido del sujeto del certificado. Anote los nombres de alias: los necesitará para la corrección.
Después, pruebe conexiones reales. Este pequeño programa se conecta a los doce hosts de prueba y funciona en Java 8 y en todas las versiones posteriores:
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 + ")");
}
}
}
}
En JDK 11 o posterior, ejecútelo con java Check.java. En Java 8, o donde solo haya un JRE instalado, compílelo primero con javac Check.java (si es necesario, en una máquina con JDK) y ejecute java Check. Una línea TRUSTED significa que este JDK acepta una intermedia comprometida. ERROR significa que no se pudo contactar con el host, lo que no demuestra nada en ningún sentido. Ejecute la comprobación con el mismo JDK y la misma configuración de truststore que su aplicación, también dentro de sus contenedores.
Cómo corregirlo
1. Eliminar las dos raíces (recomendado hasta que haya un JDK corregido)
Son las mismas dos raíces que la página de divulgación indica a los usuarios de Linux y macOS que dejen de considerar de confianza. Ejecute los comandos como el usuario propietario del JDK, con los nombres de alias que encontró en la comprobación. Por ejemplo, en Liberica JDK:
keytool -delete -cacerts -storepass changeit -alias "comodoaaaca [jdk]"
keytool -delete -cacerts -storepass changeit -alias "emsigneccrootcag3 [jdk]"
En Java 8, sustituya -cacerts por -keystore "$JAVA_HOME/jre/lib/security/cacerts". Si su truststore contiene solo una de las dos raíces, como el de Temurin, elimine solo esa.
Si no puede modificar la instalación del JDK, edite una copia y haga que la JVM la utilice:
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
En nuestras pruebas, ambos métodos hicieron que Liberica JDK 8 y 21 rechazaran los doce hosts de prueba, mientras que sitios normales como sectigo.com y github.com seguían conectando.
En las imágenes de contenedor, elimine las raíces durante la compilación para que cada nueva imagen quede corregida:
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]"
Las imágenes distroless y las que no se ejecutan como root necesitan dos cambios: no tienen shell, así que use la forma exec de RUN con un comando por línea; y se ejecutan con un usuario sin privilegios, así que cambie a USER root para la edición y vuelva después al usuario habitual de la imagen.
Consejo: Eliminar una raíz tiene un alcance mayor que bloquear ocho intermedias. Un servidor legítimo cuya cadena termine únicamente en una de estas raíces dejará de funcionar. Pruebe los servicios a los que llama su aplicación antes de desplegar este cambio, y repita la comprobación tras cada actualización del JDK, porque una actualización o reinstalación puede restaurar el cacerts original.
2. Activar la comprobación de revocación (opcional)
eMudhra ha revocado las ocho intermedias, así que una JVM que compruebe la revocación las rechaza sin ningún cambio en el truststore. Active los puntos de distribución de CRL y 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
En nuestras pruebas, esto rechazó los doce hosts de prueba en Liberica JDK 8 y 21 y en Temurin 21. Pero cambia la forma en que se valida cada certificado. La JVM hace consultas OCSP o CRL durante la validación de la ruta, y un handshake puede fallar si no se puede determinar el estado de revocación. Antes de activarlo de forma global, compruebe si los responders son accesibles desde sus servidores, cuánta latencia añaden y cómo se comportan los fallos. Úselo si ya trabaja con comprobación de revocación, o junto con la eliminación de las raíces.
3. Actualizar el JDK cuando haya builds corregidas
BellSoft ha indicado que está preparando actualizaciones de Liberica JDK que eliminan estas raíces. Siga los avisos de seguridad de su propio proveedor de JDK. Cuando se publique la actualización, lea sus notas de versión para confirmar que cubre los certificados de eMudhra, instálela, vuelva a generar sus imágenes de contenedor y repita la comprobación. Un número de versión más reciente no basta como prueba.
Después de la corrección: revise su exposición
Las claves se podían recuperar desde hace unos dieciocho meses, así que la corrección cierra la puerta, pero no le dice si alguien la usó. En los sistemas que envían credenciales o datos sensibles, busque en los registros de inspección TLS, de proxy y de endpoints certificados emitidos por las ocho intermedias de eMudhra. Si encuentra algo sospechoso, rote las credenciales afectadas.
A más largo plazo, trate los truststores como dependencias: sepa dónde está cada uno, quién lo actualiza y con qué rapidez llega un cambio a producción. Este incidente demuestra que una actualización del navegador no basta cuando sus servidores usan su propia copia de la lista de confianza.
¿Necesita ayuda? LOGIQ ofrece soporte para OpenJDK y Linux, incluida la aplicación de parches de seguridad. Si quiere ayuda para localizar todos los JDK y truststores de su entorno o para desplegar una corrección de forma segura, contacte con nosotros.
Lecturas adicionales
- eMudhra Intermediate CA Compromise: la página de divulgación, con los hosts de prueba y las versiones de paquete corregidas
- BellSoft: Distrusting compromised eMudhra intermediates in Java
Global
Japan
Korea
China
Taiwan
Vietnam
Thailand
Indonesia
Portugal
France
Germany
Egypt
Russia