CVE-2026-88900
Camel-JGroups: Unsafe Java deserialization of cluster messages in the JGroups consumer can lead to remote code execution
Description
JGroupsEndpoint.createExchange(Message), which CamelJGroupsReceiver calls for every message the jgroups consumer receives before the exchange is routed, set the exchange body from org.jgroups.Message.getObject(). For an ObjectMessage, which is the message type the Camel jgroups producer sends, JGroups Java-deserializes the payload through an ObjectInputStream on its own receive thread as the message arrives, and getObject() returns the resulting object. No java.io.ObjectInputFilter was applied on that path unless the deployment had set a JVM-wide serialization filter: camel-jgroups installed none, and the JGroups versions shipped with the affected releases apply none of their own, so any serializable class on the application classpath could be instantiated and its deserialization callbacks run. Unless a channel or the channelProperties option is configured, the consumer creates its channel with new JChannel(), the stock JGroups protocol stack, which multicasts over UDP without the AUTH protocol and without encryption, so any host able to reach the cluster's multicast group or bind port can join the cluster and send messages to the consumer without credentials. Such a host could send a crafted serialized object that leads to remote code execution in the Camel process when a usable deserialization gadget chain is present on the classpath, and no non-default option was required on the consumer. Because JGroups materializes the object before Camel's receiver runs, a check performed by Camel can only inspect the deserialized result and cannot stop code that runs during deserialization, so closing the issue also requires a control that applies before the payload is read, as described in the mitigation. Exploitation requires network access to the cluster's multicast group or bind port, which with the default UDP multicast transport means a host on an adjacent network, and a usable gadget chain on the classpath, which is why the severity is assessed as high rather than critical.
Mitigation
Credit
This issue was discovered by h1ei1
Notes
The JIRA tickets: https://issues.apache.org/jira/browse/CAMEL-24676 and https://issues.apache.org/jira/browse/CAMEL-25223 refer to the commits that resolved the issue, and have more details.
The fix was merged on main in https://github.com/apache/camel/pull/26267 (commit 0ef94ee8feabf56a5c595c07b2c60f64a73ba14e), and backported to camel-4.22.x in https://github.com/apache/camel/pull/26281 (commit da07367d1b6e2bb00ddb6afa5cfa08a6c0c0bd0f) and to camel-4.18.x in https://github.com/apache/camel/pull/26283 (commit f988494d01145473551ca75fc11cda3e5cb49f2d). The follow-up hardening of CAMEL-25223 was merged on main in https://github.com/apache/camel/pull/27205 (commit d30328a49596a04add88d32ee7ed923811c58866) and ships in 4.23.0 only. Follow-up documentation changes, https://github.com/apache/camel/pull/26282 (commit f02cde41ea679f8a3582b639b0ddd99ab723b4f0) and https://github.com/apache/camel/pull/26326 (commit d858054b98739eebf1a89f690558e1c54f09c45a), placed the 4.22.1 and 4.18.5 upgrade-guide entries on main.
CAMEL-24676 makes the consumer check the class of the body returned by Message.getObject() before the exchange is routed, through a new deserializationFilter option labelled consumer and security that takes a pattern in the jdk.serialFilter syntax. When the option is not set, the JVM-wide jdk.serialFilter is honoured if present, and otherwise a default allow-list is applied that permits standard Java and Apache Camel types, denies java.net and rejects everything else. A refused message is not routed and is reported to the consumer’s ExceptionHandler, which logs it at WARN level by default. On 4.23.0 and 4.22.1 the default is resolved through the shared DeserializationFilterHelper; on 4.18.5, where that helper does not exist, an equivalent filter is defined in the component itself. This check runs on the object that JGroups has already deserialized, so it narrows the body types that reach a route but cannot stop code that runs during deserialization: it is a defense-in-depth measure, and the component documentation of the fixed releases says so and names a JVM-wide jdk.serialFilter and a channel secured with AUTH and encryption as the controls that act before the payload is read. CAMEL-25223 makes those controls mandatory in 4.23.0: the consumer refuses to start unless at least one of them is in place, that is a JVM-wide serialization filter, the jgroups.deserialization.filter system property, which JGroups 5.5.7.Final applies to the stream it reads the payload from, or a channel whose protocol stack contains AUTH, SYM_ENCRYPT or ASYM_ENCRYPT. The deserializationFilter option does not satisfy this guard, since it acts only after the payload has been read. A new acceptAllObjects option, false by default and classified as an insecure serialization setting, restores the previous behaviour by bypassing both the guard and the class check. Producers are unaffected.
Both changes alter default behaviour and are documented in the upgrade guides: routes that exchange their own classes over the cluster must widen the class check through the deserializationFilter option, and on 4.23.0 every consumer must either have one of the controls above configured or set acceptAllObjects=true. The start-up guard is a breaking change for existing consumers on the default channel and was therefore not backported to camel-4.22.x and camel-4.18.x. The JGroups versions those lines ship, 5.5.6.Final in 4.22.1 and 5.5.2.Final in 4.18.5, also do not recognise the jgroups.deserialization.filter property, so on those lines the controls that act before the payload is read are the JVM-wide jdk.serialFilter and an authenticated, encrypted channel, which deployments must configure themselves.
The unfiltered call to Message.getObject() has been part of the consumer since camel-jgroups was first released in 2.13.0, so every release line before the fixed versions carries it. The releases from 4.0.0 through the 4.14.x line, and the 4.15.x to 4.17.x and 4.19.x to 4.21.x lines, reached end of life before this issue was resolved, and no fix will be issued for them. The camel-jgroups-raft component is not affected: it hands byte arrays to the Raft handle and does not deserialize Java objects received from the cluster.
This issue belongs to the same family as CVE-2026-40860, which concerned JMS ObjectMessage payloads deserialized when camel-jms read the message body: in both cases the deserialization is performed by the messaging library when Camel asks for the body, rather than through an ObjectInputStream that Camel constructs itself. It is classified as CWE-502 (Deserialization of Untrusted Data).