
Runnable Spring Boot proof-of-concept reproducing CVE-2026-88900, the camel-jgroups unsafe Java deserialization flaw, showing affected versus patched behavior.
Runnable proof-of-concept reproducer for the Apache Camel vulnerability where the jgroups consumer
Java-deserialized cluster messages with no filter. JGroupsEndpoint.createExchange(Message) — called for every
message the consumer receives — set the exchange body from org.jgroups.Message.getObject(). For an ObjectMessage
(the type the Camel jgroups producer sends), JGroups Java-deserializes the payload through an ObjectInputStream as
the message arrives, and getObject() returns the result. No java.io.ObjectInputFilter was applied, so any
serializable class on the application classpath received from the cluster was instantiated and its deserialization
callbacks run — remote code execution when a usable gadget chain is present. With the stock new JChannel() stack
(UDP multicast, no AUTH, no encryption), any host that can reach the cluster can send such a message without
credentials (CWE-502).
Spring Boot only. This reproducer ships a single Camel Spring Boot module.
camel-jgroupshas nocamel-quarkus-jgroupsextension, so there is no Quarkus counterpart to reproduce. The Spring Boot module demonstrates the affected and the fixed behaviour.
| Runtime | Directory | Stack |
|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-jgroups 4.22.0 (affected; fixed 4.22.1) |
A benign attacker object — com.example.Marker, an ordinary application class that is not in the fix's default
allow-list (java.**, javax.**, org.apache.camel.**) — is serialized into the JGroups wire form and fed to the
real JGroupsEndpoint.createExchange(...), which reads it with Message.getObject() (the same call the consumer makes
for every received message). No channel or multicast is needed, so the check is deterministic. Marker.readObject
flips a flag to show the deserialization callback runs — a real gadget chain would run harmful code at that exact
point; this reproducer contains no gadget.
com.example.Marker and createExchange throws
JGroupsException; the object never reaches the route.Honest caveat (as the advisory states): the 4.22.1 / 4.18.5 class check runs after JGroups has deserialized the payload, so the
readObjectcallback still runs on the fixed build too — it is defense-in-depth. To stop code that runs during deserialization you must also set a JVM-wide-Djdk.serialFilterand secure the channel withAUTH+ encryption; 4.23.0 additionally refuses to start a consumer unless one of those controls is configured. This reproducer shows the class-check differential; the callback-ran flag makes the caveat visible.
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
| Property | Value |
|---|---|
| Component | camel-jgroups (JGroupsEndpoint.createExchange) |
| CWE | CWE-502 (Deserialization of Untrusted Data) |
| Severity | HIGH |
| Attack vector | A host that can reach the cluster's multicast group / bind port sends a crafted ObjectMessage; the consumer deserializes it with no filter |
| Impact | Remote code execution in the Camel process when a gadget chain is on the classpath; arbitrary class instantiation otherwise |
| Affected Versions | From 4.0.0 before 4.18.5, from 4.19.0 before 4.22.1 |
| Fixed Versions | 4.18.5, 4.22.1, 4.23.0 |
| JIRA | CAMEL-24676, CAMEL-25223 |
| Reported by | h1ei1 |
Advisory: https://camel.apache.org/security/CVE-2026-88900.html
JGroupsEndpoint now checks the class of the body returned by
Message.getObject() before the exchange is routed, through a new deserializationFilter option (jdk.serialFilter
syntax). When it is not set, a JVM-wide jdk.serialFilter is honoured if present, otherwise a conservative default
allow-list permits java.**/javax.**/org.apache.camel.**, denies java.net.** and rejects everything else; a
refused message is reported to the consumer's ExceptionHandler and not routed. In 4.23.0 (CAMEL-25223) the consumer
also refuses to start unless a control that acts before deserialization is configured (a JVM-wide filter, the
jgroups.deserialization.filter system property, or an AUTH+encryption channel). acceptAllObjects=true restores
the old behaviour and is flagged as an insecure setting.
Set -Djdk.serialFilter on the JVM that runs the consumer (allowing only the classes your routes exchange over the
cluster), secure the channel with AUTH and SYM_ENCRYPT/ASYM_ENCRYPT via the channelProperties option, and do
not expose the cluster's multicast group or bind port to untrusted networks.
This repository is published for educational and defensive purposes: to help Apache Camel users understand the vulnerability, verify whether they are affected, and confirm that upgrading resolves it. The deserialized object is a benign marker class defined in this repository; it contains no gadget chain and performs no harmful action. Do not use this material against systems you do not own or operate.