El 30 de marzo, Mark Thomas subió a Apache Tomcat un commit titulado «Better error handling - partial revert of 6d955cc». En el fichero de código, una línea añadida y una borrada; las otras tres son la entrada del changelog, que se queda en un plano «Better error handling for the EncryptInterceptor». Lo que hacía ese cambio era mover la llamada que procesa un mensaje del clúster dentro del bloque try. Porque estaba fuera. Y estando fuera, cuando el descifrado de un mensaje fallaba, Tomcat escribía el error en el log y procesaba el mensaje igualmente.
Ese es CVE-2026-34486, que el 4 de agosto entró en el catálogo de vulnerabilidades explotadas de CISA con plazo de corrección para el día 7 —el mismo lote en el que iba el 9,8 de Langflow del que hablamos por la mañana—. Conviene decir de dónde sale cada número, porque no vienen del mismo sitio: Apache, como CNA, se limitó a clasificarlo «Important», sin puntuación; el 9,8 que verás en el NVD lo añadió CISA —acceso por red, sin autenticación previa, sin interacción del usuario, impacto alto en las tres patas—; y Red Hat, mirando el mismo fallo, se queda en 7,5. Tres lecturas distintas que coinciden en lo único que hay que retener: se llega por red y no hace falta credencial. Todo eso, por una línea en el sitio equivocado.
Qué protege el EncryptInterceptor
Cuando montas varios Tomcat en clúster para que la sesión de un usuario sobreviva a la caída de un nodo, los nodos se hablan entre ellos por un canal propio —Tribes— que escucha en el puerto 4000 por defecto. Por ahí no viajan peticiones HTTP: viajan objetos Java serializados. Es literal en la documentación del proyecto: todos los atributos de sesión tienen que implementar java.io.Serializable, y lo que se manda por el socket TCP es «the serialized data».
La propia documentación de Tomcat abre el capítulo de seguridad del clúster con una frase que conviene leer despacio: «la implementación del clúster está escrita partiendo de la base de que se usa una red segura y de confianza para todo el tráfico del clúster. No es seguro ejecutar un clúster en una red insegura y no confiable». Y sobre el interceptor de cifrado dice que, bien configurado, aporta confidencialidad e integridad, pero que no protege de todos los riesgos de correr el clúster en una red que no controlas. El EncryptInterceptor no es la puerta: es el candado que le pones a una puerta que ya debería estar dentro de casa.
El parche del parche
La cronología es pública y se puede seguir commit a commit. Merece la pena, porque explica por qué acabó pasando:
- →22 de febrero de 2026: alguien reporta CVE-2026-29146. El EncryptInterceptor usaba CBC por defecto, vulnerable a un ataque de padding oracle. Un fallo real, de los de libro de texto.
- →13 de marzo: llega el arreglo, un commit grande que añade soporte para más algoritmos, cambia la recomendación a
AES/GCM/NoPaddingy mete un aviso en el log cuando detecta el algoritmo inseguro. Buen trabajo. Y de paso, entre las 64 líneas que cambia en ese fichero, saca la llamadasuper.messageReceived(msg)fuera deltry. - →20 de marzo: sale Tomcat 11.0.20 con ese arreglo dentro. (La 11.0.19 existió pero no pasó la votación de publicación, así que para tener el parche había que ir a la 20.)
- →26 de marzo: seis días después, alguien reporta que ese arreglo se puede saltar. Es CVE-2026-34486.
- →30 de marzo: el commit de una línea, descrito como «reversión parcial» del anterior. Las versiones corregidas salen el 2, el 3 y el 4 de abril (10.1.54, 9.0.117 y 11.0.21).
- →9 de abril: se publican los dos CVE. 4 de agosto: CISA mete el segundo en el KEV. Cuatro meses justos desde que salió la última versión corregida hasta que hubo gente usándolo para entrar.
Fallar abriendo
El código vulnerable, resumido, era este:
Y la corrección: la misma llamada, dentro del try. Nada más.
Conviene aterrizar qué es eso que «pasa igual», porque en abstracto suena inofensivo: es un objeto Java que nadie ha podido verificar entrando en la cadena de procesamiento del clúster, la misma que acaba deserializando sesiones. En la valoración que CISA adjunta al registro del NVD, con fecha del 4 de agosto, la explotación figura como activa y automatizable. CISA no publica cómo se está usando, y nosotros no lo vamos a inventar; con esos dos adjetivos y un plazo de tres días para las agencias federales ya hay suficiente para mover la actualización de la lista de «pendiente» a la de «hoy».
Lo llamativo no es el descuido —el descuido es humano y cualquiera que haya escrito Java lo ha hecho—. Lo llamativo es hacia dónde falla. Un control de seguridad puede fallar de dos maneras: cerrando (si no puedo verificar esto, lo tiro) o abriendo (si no puedo verificar esto, lo dejo pasar y apunto una nota). La primera provoca incidencias de disponibilidad y llamadas al soporte. La segunda no provoca nada: todo sigue funcionando, los usuarios no se quejan, los gráficos están verdes y la protección lleva semanas apagada.
Y ojo al detalle que más nos interesa: la señal existía. Cada mensaje que no se podía descifrar dejaba un Failed to decrypt message en el log del nodo. No estamos ante un fallo silencioso: estamos ante un fallo que avisaba y que nadie estaba escuchando. Un clúster sano no genera ese mensaje nunca; verlo aparecer significa, como mínimo, que dos nodos no comparten la misma clave, y como máximo, que alguien está mandando cosas a tu puerto 4000. Es exactamente el tipo de línea que debería tener una alerta detrás, y de esto ya escribimos en su día en el post sobre fatiga de alertas: el problema casi nunca es que falte información, es que sobra y nadie distingue qué línea importa.
El fallo solo afectaba a quien se había molestado en cifrar
Aquí viene la parte incómoda. Mira las versiones afectadas que publica el NVD: 11.0.20, 10.1.53 y 9.0.116. No «de la tal a la cual». Tres versiones sueltas. Exactamente las tres que traían el parche del padding oracle. Quien iba una versión por detrás nunca estuvo expuesto a esto (tenía el fallo anterior, que tampoco es un premio). Y el EncryptInterceptor no viene activado: hay que añadirlo a mano al pipeline de interceptores del canal. Es decir, para comerte este CVE tenías que cumplir tres condiciones seguidas: tener clúster, haberte molestado en cifrar el canal, y haber actualizado deprisa.
Esto se puede contar como una moraleja perezosa —«ya ves, por correr»— y sería una tontería peligrosa. La versión con el fallo estuvo publicada quince días en la rama 11.0, del 20 de marzo al 4 de abril; el otro camino era quedarse con un cifrado que se podía romper por otro lado. No hay opción buena entre las dos. La conclusión útil es otra y es aburrida: lo que te salva no es parchear rápido o lento, es saber en qué versión exacta estás y poder cambiarla el mismo día que haga falta. Si te enteras hoy de que 11.0.20 tenía esto y no sabes de memoria —o con un comando— qué corre cada uno de tus nodos, ese es el problema a arreglar, no el ritmo. Lo escribimos con más detalle en «latest no es una versión», y este caso lo ilustra mejor que nosotros.
«Better error handling»
La entrada del changelog de la versión corregida dice, literalmente, «Better error handling for the EncryptInterceptor». Nada de «bypass», nada de «security». Que conste que el proyecto hizo lo correcto: publicó el CVE en su página de seguridad, con la severidad, las versiones afectadas y el enlace al commit. Pero si tu proceso para decidir si una actualización es urgente consiste en leer el changelog y ver si «suena a seguridad», este es el contraejemplo perfecto. El changelog cuenta qué cambió; la página de seguridad del proyecto cuenta qué te puede pasar si no cambias. Son dos documentos distintos y solo uno sirve para priorizar.
Los cinco minutos de esta tarde
Si tienes Java en producción —y hay mucha más de la que aparece en los inventarios, normalmente debajo de una aplicación de gestión que compró otro departamento hace ocho años—, esto es lo que miramos nosotros:
- ✓La versión exacta, en cada nodo. No la del inventario: la del proceso que está corriendo ahora mismo. Si sale 11.0.20, 10.1.53 o 9.0.116, hay trabajo hoy.
- ✓¿Está el bloque
<Cluster>activo en elserver.xml? Los clústeres declarados que nadie usa, heredados de una plantilla, son más comunes de lo que parece. Si no replicas sesiones, ese bloque no debería estar ahí. - ✓¿Quién llega al rango 4000-4100? Ese es el puerto por defecto del receptor y los cien siguientes, porque Tomcat autoenlaza al primero libre. Desde fuera del segmento de los nodos, la respuesta tiene que ser «nadie». No porque el cifrado sea malo, sino porque el cifrado es la segunda línea y esta semana hemos visto lo que pasa cuando la segunda línea se apaga sola.
- ✓Una alerta sobre
Failed to decrypt message. Y sobre el aviso de algoritmo inseguro que el propio Tomcat escribe si sigues en CBC. Dos líneas de log, dos alertas, diez minutos de trabajo. - ✓Cómo te enteras del próximo. El feed del KEV de CISA y la página de seguridad de los productos que tienes en producción, leídos por alguien con nombre y apellidos. Es la parte menos vistosa de la ciberseguridad gestionada y la que más veces evita el susto.
Y una cosa que no está en el aviso pero sí en la documentación de Tomcat desde siempre: el tráfico entre nodos de un clúster no debería salir nunca de un segmento que controlas. Cuando los nodos están en sitios distintos —dos oficinas, dos centros de datos—, eso significa un túnel, no «la IP pública y ya cifra el interceptor». Es la conversación que tenemos cada vez que alguien nos pide montar la red entre sedes: qué va por dentro y qué va por fuera, y quién puede hablar con quién.
¿Cuántos de tus controles fallan abriendo?
Esta es la pregunta que nos llevamos del caso, y no tiene nada que ver con Tomcat. El proxy que inspecciona la salida a internet: si se cae, ¿el tráfico se corta o sale directo? El filtro antispam: si el análisis expira, ¿retiene el correo o lo entrega? El acceso condicional: si el servicio que evalúa la política no responde, ¿deniega o concede? El agente de EDR: si el servicio está parado, ¿alguien se entera el mismo día? Cada una de esas respuestas es una decisión de diseño que alguien tomó, muchas veces sin escribirla en ningún sitio, y casi siempre a favor de que las cosas sigan funcionando. Es una decisión legítima —hay sistemas donde fallar cerrando es peor que el ataque—, pero tiene que ser una decisión, no una casualidad heredada.
Nosotros hemos escrito ese catch. Todo el que lleva años tocando código lo ha escrito: capturas la excepción para que el servicio no se caiga a las tres de la mañana, y con eso conviertes un error ruidoso en uno silencioso. Por eso la regla que aplicamos cuando revisamos una arquitectura no es «¿está el cifrado activado?», sino «¿qué pasa exactamente cuando esto falla, y quién se entera?». La primera pregunta se responde con una captura de pantalla. La segunda hay que probarla: apagar el control a propósito, en una ventana, y mirar si algo se rompe o si alguien avisa. Si no se rompe nada y no avisa nadie, ya sabes hacia dónde falla.
Si no tienes claro qué hay corriendo debajo de tus aplicaciones —o lo tienes claro pero nadie mira los logs de esas máquinas—, escríbenos. La primera conversación suele ser corta: qué versiones, quién llega a qué, y qué pasa cuando algo se rompe.
Fuentes (verificadas): CVE-2026-34486, «Missing Encryption of Sensitive Data vulnerability in Apache Tomcat due to the fix for CVE-2026-29146 allowing the bypass of the EncryptInterceptor», afecta a 11.0.20, 10.1.53 y 9.0.116, corregido en 11.0.21, 10.1.54 y 9.0.117, CVSS 3.1 de 9,8 (crítico, vector AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) añadido por CISA-ADP como métrica secundaria en el NVD, no por el proyecto: la Apache Software Foundation, como CNA, solo lo clasificó «Important» sin puntuación, y Red Hat lo valora en 7,5; la valoración SSVC de CISA Coordinator del 04-08-2026 incluida en el propio registro marca «exploitation: active» y «automatable: yes». Publicado el 09-04-2026 — NVD; clasificación «Important», fechas de reporte (26-03-2026) y publicación, y enlaces a los commits — avisos de seguridad de Apache Tomcat 11 (equivalentes para las ramas 10.1 y 9.0); CVE-2026-29146 (EncryptInterceptor con CBC por defecto, vulnerable a padding oracle, reportado el 22-02-2026); commits 6d955cce (13-03-2026) y 1fab40cc (30-03-2026, «Better error handling - partial revert of 6d955cc», 2 ficheros, 4 inserciones y 1 borrado) — repositorio de Apache Tomcat; puerto 4000 por defecto del receptor Tribes, requisito de java.io.Serializable, red de confianza y alcance del EncryptInterceptor — documentación de clustering de Tomcat 11; mensajes de log encryptInterceptor.decrypt.failed y encryptInterceptor.algorithm.switch — fichero LocalStrings.properties del propio proyecto; inclusión en el catálogo de vulnerabilidades explotadas el 04-08-2026 con plazo el 07-08-2026 — CISA KEV. CISA no publica detalles de cómo se está explotando; nosotros no los inventamos. Las lecturas, la regla del fail-open y las recomendaciones operativas son nuestras.
¿Sabes hacia dónde fallan tus controles?
En everyWAN revisamos versiones, quién llega a qué y qué ocurre cuando una protección deja de funcionar. Sin sustos y sin diapositivas: comandos, logs y una lista de lo que hay que arreglar.
Hablar con everyWAN