
Preuve de concept Spring Boot exécutable reproduisant CVE-2026-88900, la faille de désérialisation Java non sécurisée de camel-jgroups, illustrant le comportement affecté par rapport au comportement corrigé.
Reproducteur de preuve de concept exécutable pour la vulnérabilité Apache Camel où le consommateur jgroups
désérialisait en Java les messages de cluster sans aucun filtre. JGroupsEndpoint.createExchange(Message) — appelé pour chaque
message reçu par le consommateur — définissait le corps de l'échange à partir de org.jgroups.Message.getObject(). Pour un ObjectMessage
(le type envoyé par le producteur jgroups de Camel), JGroups désérialise en Java la charge utile via un ObjectInputStream à
l'arrivée du message, et getObject() renvoie le résultat. Aucun java.io.ObjectInputFilter n'était appliqué, donc toute
classe sérialisable présente sur le classpath de l'application et reçue depuis le cluster était instanciée et ses callbacks de
désérialisation exécutés — exécution de code à distance lorsqu'une chaîne de gadgets exploitable est présente. Avec la pile
standard new JChannel() (multicast UDP, sans AUTH, sans chiffrement), tout hôte capable d'atteindre le cluster peut envoyer un tel message sans
identifiants (CWE-502).
Spring Boot uniquement. Ce reproducteur ne contient qu'un seul module Camel Spring Boot.
camel-jgroupsn'a pas d'extensioncamel-quarkus-jgroups, il n'y a donc pas d'équivalent Quarkus à reproduire. Le module Spring Boot démontre le comportement affecté et le comportement corrigé.
| Runtime | Répertoire | Pile |
|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-jgroups 4.22.0 (affecté ; corrigé en 4.22.1) |
Un objet attaquant bénin — com.example.Marker, une classe applicative ordinaire qui n'est pas dans la liste d'autorisation
par défaut du correctif (java.**, javax.**, org.apache.camel.**) — est sérialisé dans la forme filaire JGroups et fourni au
véritable JGroupsEndpoint.createExchange(...), qui le lit avec Message.getObject() (le même appel que le consommateur effectue
pour chaque message reçu). Aucun canal ni multicast n'est nécessaire, la vérification est donc déterministe. Marker.readObject
bascule un indicateur pour montrer que le callback de désérialisation s'exécute — une véritable chaîne de gadgets exécuterait du code malveillant à cet
endroit précis ; ce reproducteur ne contient aucun gadget.
com.example.Marker et createExchange lève
une JGroupsException ; l'objet n'atteint jamais la route.Mise en garde honnête (comme l'indique l'avis) : la vérification de classe des versions 4.22.1 / 4.18.5 s'exécute après que JGroups a désérialisé la charge utile, donc le callback
readObjects'exécute également sur la version corrigée — c'est une défense en profondeur. Pour empêcher le code qui s'exécute pendant la désérialisation, vous devez également définir un-Djdk.serialFilterà l'échelle de la JVM et sécuriser le canal avecAUTH+ chiffrement ; la version 4.23.0 refuse en outre de démarrer un consommateur à moins que l'un de ces contrôles ne soit configuré. Ce reproducteur montre le différentiel de vérification de classe ; l'indicateur d'exécution du callback rend la mise en garde 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
| Propriété | Valeur |
|---|---|
| Composant | camel-jgroups (JGroupsEndpoint.createExchange) |
| CWE | CWE-502 (Désérialisation de données non fiables) |
| Gravité | ÉLEVÉE |
| Vecteur d'attaque | Un hôte capable d'atteindre le groupe multicast / le port de liaison du cluster envoie un ObjectMessage forgé ; le consommateur le désérialise sans aucun filtre |
| Impact | Exécution de code à distance dans le processus Camel lorsqu'une chaîne de gadgets se trouve sur le classpath ; sinon, instanciation arbitraire de classes |
| Versions affectées | À partir de 4.0.0 avant 4.18.5, à partir de 4.19.0 avant 4.22.1 |
| Versions corrigées | 4.18.5, 4.22.1, 4.23.0 |
| JIRA | CAMEL-24676, CAMEL-25223 |
| Signalé par | h1ei1 |
Avis de sécurité : https://camel.apache.org/security/CVE-2026-88900.html
JGroupsEndpoint vérifie désormais la classe du corps renvoyé par
Message.getObject() avant que l'échange ne soit routé, via une nouvelle option deserializationFilter (syntaxe
jdk.serialFilter). Lorsqu'elle n'est pas définie, un jdk.serialFilter à l'échelle de la JVM est respecté s'il est
présent ; sinon, une liste d'autorisation par défaut conservatrice autorise java.**/javax.**/org.apache.camel.**,
refuse java.net.** et rejette tout le reste ; un message refusé est signalé au ExceptionHandler du consommateur et
n'est pas routé. Dans 4.23.0 (CAMEL-25223), le consommateur refuse également de démarrer sauf si un contrôle agissant
avant la désérialisation est configuré (un filtre à l'échelle de la JVM, la propriété système
jgroups.deserialization.filter, ou un canal AUTH+chiffrement). acceptAllObjects=true restaure l'ancien comportement
et est signalé comme un paramètre non sécurisé.
Définissez -Djdk.serialFilter sur la JVM qui exécute le consommateur (en n'autorisant que les classes que vos routes
échangent sur le cluster), sécurisez le canal avec AUTH et SYM_ENCRYPT/ASYM_ENCRYPT via l'option
channelProperties, et n'exposez pas le groupe multicast ni le port de liaison du cluster à des réseaux non fiables.
Ce dépôt est publié à des fins éducatives et défensives : pour aider les utilisateurs d'Apache Camel à comprendre la vulnérabilité, à vérifier s'ils sont affectés et à confirmer que la mise à jour la résout. L'objet désérialisé est une classe marqueur bénigne définie dans ce dépôt ; elle ne contient aucune chaîne de gadgets et n'effectue aucune action nuisible. N'utilisez pas ce contenu contre des systèmes que vous ne possédez pas ou n'exploitez pas.