
Reproducer per CVE-2026-40860 — deserializzazione non sicura di JMS ObjectMessage in Apache Camel camel-jms/sjms/amqp (RCE)
Questo progetto dimostra una vulnerabilità di deserializzazione Java nel componente camel-jms di Apache Camel
(e, transitivamente, camel-sjms, camel-sjms2, camel-amqp, camel-activemq, camel-activemq6),
identificata come CVE-2026-40860. JmsBinding.extractBodyFromJms() deserializza il payload di un
JMS ObjectMessage in arrivo tramite ObjectMessage.getObject() senza ObjectInputFilter, lista
di classi consentite o negate. Poiché questo avviene ogni volta che mapJmsMessage=true (impostazione predefinita) e Camel è un JMS consumer,
un attaccante in grado di pubblicare un ObjectMessage appositamente costruito su una coda/topic consumata può ottenere esecuzione
di codice in remoto quando una catena di gadget è nel classpath.
Advisory: https://camel.apache.org/security/CVE-2026-40860.html
// 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() esegue il ObjectInputStream.readObject() del provider JMS sul corpo del messaggio. Camel non aggiunge alcun
filtro di classi proprio, quindi una catena di gadget presente nel classpath viene eseguita durante la deserializzazione.
La correzione (4.14.7 / 4.18.2 / 4.20.0) aggiunge una allow-list predefinita di ObjectInputFilter
(java.**;javax.**;org.apache.camel.**;!*), personalizzabile tramite la nuova opzione di endpoint deserializationFilter
o tramite il filtro globale JVM -Djdk.serialFilter. Da notare quanto riportato nel messaggio di commit di Camel per la correzione:
questo controllo viene eseguito dopo che il provider JMS ha già deserializzato il payload. Impedisce che classi inattese vengano propagate alla route, ma da solo non può fermare le catene di gadget il cui
readObject()scatta all'interno diObjectInputStreamdel provider. Una protezione completa richiede di configurare il filtro di deserializzazione del provider JMS e/o il filtro JVM globale-Djdk.serialFilter.
Quindi la protezione completa = aggiornare Camel + limitare il provider / il filtro JVM. Questa PoC usa un client ActiveMQ
con trustAllPackages=true (un'impostazione comune negli ambienti reali) così il provider deserializza il payload;
su una versione vulnerabile di Camel non c'è altro a impedirlo.
from("jms:queue:evil") // mapJmsMessage defaults to true
.log("Consumed: ${body.class.name}");
Il semplice ricevimento dell'ObjectMessage attiva la deserializzazione — il corpo della route è irrilevante.
La vittima è il consumer JMS di Camel. L'attaccante è qualsiasi producer che può pubblicare sulla coda. Entrambi comunicano con un broker reale Apache ActiveMQ Artemis in esecuzione in 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
In un attacco reale, i byte serializzati sono prodotti offline dall'attaccante (ad es. con ysoserial); solo la vittima ha bisogno della catena di gadget nel proprio classpath. Questa PoC costruisce il gadget in-process per comodità, ed è per questo che la JVM viene eseguita con
--add-opens java.base/java.util=ALL-UNNAMED— un dettaglio di costruzione del gadget, non correlato alla vulnerabilità.
mvn clean package -DskipTests
docker compose up -d --build
Questo avvia un broker Artemis (quay.io/artemiscloud/activemq-artemis-broker) e l'app di riproduzione,
che si connette ad esso tramite 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
Qualsiasi consumer JMS di Camel (camel-jms, camel-sjms, camel-sjms2, camel-amqp, camel-activemq,
camel-activemq6) che legge da una destinazione su cui un attaccante può pubblicare — un broker condiviso, un topic con
producer aperti, una coda alimentata da un upstream non attendibile — con mapJmsMessage=true (predefinito).
mapJmsMessage=true (predefinito).ObjectMessage alla destinazione consumata.trustAllPackages=true, oppure un provider senza
un filtro restrittivo).commons-collections:3.2.1).Aggiornare a 4.14.7 / 4.18.2 / 4.20.0 e limitare la deserializzazione end-to-end:
-Djdk.serialFilter=java.**;org.apache.camel.**;!* (oppure la nuova
opzione deserializationFilter dell'endpoint).trustedPackages; non
usare trustAllPackages=true).Fino all'aggiornamento:
ObjectMessage; impostare mapJmsMessage=false dove il messaggio grezzo è accettabile.trustAllPackages=true su destinazioni non attendibili.-Djdk.serialFilter.Questo riproduttore è fornito solo per ricerca sulla sicurezza e test autorizzati, per una vulnerabilità pubblicamente divulgata e corretta. Non usarlo contro sistemi senza autorizzazione esplicita.
| Proprietà | Valore |
|---|
| Componenti | camel-jms (+ camel-sjms, camel-sjms2, camel-amqp, camel-activemq, camel-activemq6) |
| Classe interessata | org.apache.camel.component.jms.JmsBinding#extractBodyFromJms → jakarta.jms.ObjectMessage#getObject() |
| CWE | CWE-502: Deserializzazione di dati non attendibili |
| Impatto | Esecuzione di codice in remoto (RCE) |
| Attivazione | Consumer JMS di Camel + mapJmsMessage=true (predefinito) + un ObjectMessage che l'attaccante può accodare |
| Versioni interessate | Dalla 3.0.0 prima della 4.14.7, dalla 4.15.0 prima della 4.18.2, dalla 4.19.0 prima della 4.20.0 |
| Versioni corrette | 4.14.7, 4.18.2, 4.20.0 |
| JIRA | CAMEL-23321 |
| Segnalatore | Venkatraman Kumar (Securin) |