
Reproducción de CVE: cve-2026-34486-tomcat_encrypt_bypass_reproduction
| Campo | Valor |
|---|---|
| CVE | CVE-2026-34486 |
| CVSS | 7.5 HIGH |
| Tipo | Falta de cifrado de datos sensibles |
| Componente | Apache Tomcat Cluster EncryptInterceptor |
| Publicado | 2026 |
CVE-2026-34486 es una regresión introducida por la corrección incompleta de CVE-2026-29146. En la replicación de clúster de Apache Tomcat, el EncryptInterceptor es responsable de cifrar y autenticar los mensajes del clúster. Una refactorización en la corrección de CVE-2026-29146 movió inadvertidamente la llamada a super.messageReceived(msg) fuera del bloque try-catch que maneja los fallos de descifrado. Como resultado, cuando un mensaje falla al descifrarse (es decir, se recibe en texto plano pero el interceptor espera datos cifrados), el mensaje sin cifrar se pasa igualmente a la cadena de manejadores en lugar de descartarse.
El método EncryptInterceptor.messageReceived() se invoca cuando llega un mensaje del clúster. El flujo esperado es:
super.messageReceived(msg) para reenviar el mensaje descifradoEn las versiones vulnerables, la lógica de descifrado/validación permanece envuelta en un try-catch, pero la cadena de llamadas se reestructuró de modo que super.messageReceived(msg) se ejecuta fuera del bloque try-catch que protege el descifrado. La variable msg se declara antes del try-catch y se asigna dentro de él. Cuando el descifrado lanza una excepción, msg conserva su valor inicial (sin cifrar/sin procesar), y el bloque catch solo registra el error — no retorna temprano. La ejecución continúa hacia super.messageReceived(msg) con los datos sin procesar.
Esto significa que un atacante que pueda alcanzar el puerto del clúster de Tomcat puede inyectar mensajes arbitrarios sin cifrar que el interceptor aceptará y procesará.
public void messageReceived(Message msg) {
// msg llega sin procesar
try {
// descifrar y rellenar los campos de msg
decrypt(msg);
} catch (Exception e) {
log.error("Falló el descifrado", e);
// ERROR: no hay declaración return aquí
}
// msg sigue siendo el objeto original sin cifrar cuando se alcanza el catch
super.messageReceived(msg); // fuera del try-catch → pasa datos sin procesar
}
La corrección debe garantizar que:
super.messageReceived(msg) se llame solo dentro del bloque try después de un descifrado exitoso, o| Producto | Versiones |
|---|---|
| Apache Tomcat 11 | 11.0.20 |
| Apache Tomcat 10 | 10.1.53 |
| Apache Tomcat 9 | 9.0.116 |
EncryptInterceptor<Receiver>)EncryptInterceptor en server.xml.El script exploit.py en este directorio demuestra la omisión. Construye un mensaje mínimo de clúster de Tomcat (basado en el formato de serialización de ClusterMessage) y lo envía directamente al puerto del receptor sin ningún cifrado. Un interceptor vulnerable aceptará y reenviará el mensaje a pesar de la falta de cifrado.
Actualice a una versión parcheada de Apache Tomcat:
| Producto | Versión parcheada |
|---|---|
| Apache Tomcat 11 | 11.0.21+ |
| Apache Tomcat 10 | 10.1.54+ |
| Apache Tomcat 9 | 9.0.117+ |
Si no es posible actualizar de inmediato, restrinja el acceso de red al puerto del clúster de Tomcat solo a hosts de confianza (por ejemplo, mediante reglas de firewall o vinculando el receptor a una interfaz loopback o privada).