
Proof-of-concept eseguibile in Spring Boot che riproduce CVE-2026-88900, la vulnerabilità di deserializzazione Java non sicura in camel-jgroups, mostrando il comportamento vulnerabile rispetto a quello corretto.
Riproduttore proof-of-concept eseguibile per la vulnerabilità di Apache Camel in cui il consumer jgroups
deserializzava in Java i messaggi di cluster senza alcun filtro. JGroupsEndpoint.createExchange(Message) — invocato per ogni
messaggio ricevuto dal consumer — impostava il body dello scambio da org.jgroups.Message.getObject(). Per un ObjectMessage
(il tipo inviato dal producer jgroups di Camel), JGroups deserializza in Java il payload tramite un ObjectInputStream non appena
il messaggio arriva, e getObject() restituisce il risultato. Non veniva applicato alcun java.io.ObjectInputFilter, quindi qualsiasi
classe serializzabile presente nel classpath dell'applicazione e ricevuta dal cluster veniva istanziata e i suoi callback di deserializzazione
eseguiti — esecuzione di codice remoto in presenza di una catena di gadget utilizzabile. Con lo stack predefinito new JChannel()
(UDP multicast, senza AUTH, senza cifratura), qualsiasi host in grado di raggiungere il cluster può inviare un tale messaggio senza
credenziali (CWE-502).
Solo Spring Boot. Questo riproduttore include un unico modulo Camel Spring Boot.
camel-jgroupsnon ha un'estensionecamel-quarkus-jgroups, quindi non esiste una controparte Quarkus da riprodurre. Il modulo Spring Boot dimostra il comportamento affetto e quello corretto.
| Runtime | Directory | Stack |
|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-jgroups 4.22.0 (affetto; corretto in 4.22.1) |
Un oggetto attaccante benigno — com.example.Marker, una normale classe dell'applicazione che non è nella allow-list
predefinita della correzione (java.**, javax.**, org.apache.camel.**) — viene serializzato nel formato di rete di JGroups e passato
al reale JGroupsEndpoint.createExchange(...), che lo legge con Message.getObject() (la stessa chiamata che il consumer effettua
per ogni messaggio ricevuto). Non sono necessari canale o multicast, quindi il controllo è deterministico. Marker.readObject
imposta un flag per mostrare che il callback di deserializzazione viene eseguito — una vera catena di gadget eseguirebbe codice dannoso esattamente in quel
punto; questo riproduttore non contiene alcun gadget.
com.example.Marker e createExchange lancia
JGroupsException; l'oggetto non raggiunge mai la route.Avvertenza onesta (come afferma l'advisory): il controllo delle classi di 4.22.1 / 4.18.5 viene eseguito dopo che JGroups ha deserializzato il payload, quindi il callback
readObjectviene eseguito anche nella build corretta — si tratta di difesa in profondità. Per fermare il codice che viene eseguito durante la deserializzazione è necessario impostare anche un-Djdk.serialFiltera livello di JVM e proteggere il canale conAUTH+ cifratura; 4.23.0 inoltre rifiuta di avviare un consumer a meno che uno di questi controlli non sia configurato. Questo riproduttore mostra il differenziale del controllo delle classi; il flag che indica l'esecuzione del callback rende visibile l'avvertenza.
cd camel-spring-boot
mvn clean package
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack # affected: Marker deserialized + routed; >>> PROVEN
docker compose down
# Patched control
mvn clean package -Dcamel.version=4.22.1
java -jar target/cve-2026-88900-jgroups-deserialization-0.0.1-SNAPSHOT.jar &
curl -s http://localhost:8080/exploit/attack # fixed: JGroupsException rejects com.example.Marker; >>> Not exploited
| Proprietà | Valore |
|---|---|
| Componente | camel-jgroups (JGroupsEndpoint.createExchange) |
| CWE | CWE-502 (Deserializzazione di dati non attendibili) |
| Gravità | ALTA |
| Vettore di attacco | Un host in grado di raggiungere il gruppo multicast / la porta di bind del cluster invia un ObjectMessage appositamente costruito; il consumer lo deserializza senza alcun filtro |
| Impatto | Esecuzione di codice remoto nel processo Camel quando una gadget chain è presente nel classpath; in caso contrario, istanziazione arbitraria di classi |
| Versioni interessate | Dalla 4.0.0 precedente alla 4.18.5, dalla 4.19.0 precedente alla 4.22.1 |
| Versioni corrette | 4.18.5, 4.22.1, 4.23.0 |
| JIRA | CAMEL-24676, CAMEL-25223 |
| Segnalato da | h1ei1 |
Advisory: https://camel.apache.org/security/CVE-2026-88900.html
JGroupsEndpoint ora verifica la classe del body restituito da
Message.getObject() prima che lo scambio venga instradato, tramite una nuova opzione deserializationFilter (sintassi
jdk.serialFilter). Quando non è impostata, viene rispettato un jdk.serialFilter a livello di JVM se presente, altrimenti
una allow-list predefinita conservativa consente java.**/javax.**/org.apache.camel.**, nega java.net.** e rifiuta
tutto il resto; un messaggio rifiutato viene segnalato all'ExceptionHandler del consumer e non viene instradato. Nella
4.23.0 (CAMEL-25223) il consumer inoltre rifiuta di avviarsi a meno che non sia configurato un controllo che agisce
prima della deserializzazione (un filtro a livello di JVM, la proprietà di sistema jgroups.deserialization.filter, oppure
un canale AUTH+cifratura). acceptAllObjects=true ripristina il vecchio comportamento ed è segnalato come impostazione
non sicura.
Impostare -Djdk.serialFilter sulla JVM che esegue il consumer (consentendo solo le classi che le proprie route scambiano
sul cluster), proteggere il canale con AUTH e SYM_ENCRYPT/ASYM_ENCRYPT tramite l'opzione channelProperties, e non
esporre il gruppo multicast o la porta di bind del cluster a reti non attendibili.
Questo repository è pubblicato per scopi educativi e difensivi: per aiutare gli utenti di Apache Camel a comprendere la vulnerabilità, verificare se sono interessati e confermare che l'aggiornamento la risolve. L'oggetto deserializzato è una classe marcatore benigna definita in questo repository; non contiene alcuna gadget chain e non esegue alcuna azione dannosa. Non utilizzare questo materiale contro sistemi di cui non si è proprietari o che non si gestiscono.