Share
## https://sploitus.com/exploit?id=8E0B8D72-3CB0-5BE2-8855-826D1289F52E
# camel-jms JMS ObjectMessage Unsafe Deserialization Reproducer (CVE-2026-40860)

This project demonstrates a **Java deserialization vulnerability** in Apache Camel's `camel-jms` component
(and, transitively, `camel-sjms`, `camel-sjms2`, `camel-amqp`, `camel-activemq`, `camel-activemq6`),
tracked as **CVE-2026-40860**. `JmsBinding.extractBodyFromJms()` deserializes the payload of an incoming
JMS **`ObjectMessage`** via `ObjectMessage.getObject()` with **no `ObjectInputFilter`**, class allow-list
or deny-list. Because this runs whenever `mapJmsMessage=true` (the default) and Camel is a JMS **consumer**,
an attacker able to publish a crafted `ObjectMessage` to a consumed queue/topic can achieve **remote code
execution** when a gadget chain is on the classpath.

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

## Vulnerability Summary

| Property | Value |
|----------|-------|
| **Components** | `camel-jms` (+ `camel-sjms`, `camel-sjms2`, `camel-amqp`, `camel-activemq`, `camel-activemq6`) |
| **Affected Class** | `org.apache.camel.component.jms.JmsBinding#extractBodyFromJms` โ†’ `jakarta.jms.ObjectMessage#getObject()` |
| **CWE** | CWE-502: Deserialization of Untrusted Data |
| **Impact** | Remote Code Execution (RCE) |
| **Trigger** | Camel JMS consumer + `mapJmsMessage=true` (default) + an `ObjectMessage` the attacker can enqueue |
| **Affected Versions** | From 3.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-23321 |
| **Reporter** | Venkatraman Kumar (Securin) |

## Technical Details

```java
// JmsBinding.extractBodyFromJms(Exchange, Message) - affected version
if (message instanceof ObjectMessage objectMessage) {
    Object payload = objectMessage.getObject();   //  *this check runs **after** the JMS provider has already deserialized the payload. It prevents unexpected
> classes from being propagated to the route, but it cannot, on its own, stop gadget chains whose
> `readObject()` fires inside the provider's `ObjectInputStream`. Complete protection requires configuring
> the JMS provider's own deserialization filter and/or the JVM-wide `-Djdk.serialFilter`.*

So full protection = **upgrade Camel + constrain the provider / JVM filter**. This PoC uses an ActiveMQ
client with `trustAllPackages=true` (a common real-world setting) so the provider deserializes the payload;
on an affected Camel version nothing else stands in the way.

## The victim route

```java
from("jms:queue:evil")            // mapJmsMessage defaults to true
    .log("Consumed: ${body.class.name}");
```

Merely **receiving** the `ObjectMessage` triggers the deserialization โ€” the route body is irrelevant.

## Repository layout โ€” attacker vs. victim

The **victim** is the Camel JMS consumer. The **attacker** is any producer that can publish to the queue.
Both talk to a real **Apache ActiveMQ Artemis** broker running in Docker.

```
CVE-2026-40860/
โ”œโ”€โ”€ pom.xml                 # camel-jms 4.18.1 + activemq-client 6.2.4 + commons-collections 3.2.1 (gadget)
โ”œโ”€โ”€ Dockerfile              # runs the app (--add-opens only to build the gadget)
โ”œโ”€โ”€ docker-compose.yml      # Artemis broker (quay.io) + the reproducer app
โ”œโ”€โ”€ README.md
โ””โ”€โ”€ src/main/
    โ”œโ”€โ”€ java/com/example/
    โ”‚   โ”œโ”€โ”€ Application.java
    โ”‚   โ”œโ”€โ”€ JmsConfig.java          # OpenWire ConnectionFactory (trustAllPackages=true) + jms component
    โ”‚   โ”œโ”€โ”€ VictimRoute.java        # victim: from("jms:queue:evil")
    โ”‚   โ”œโ”€โ”€ Gadget.java             # CommonsCollections6 gadget, fires during getObject()
    โ”‚   โ””โ”€โ”€ ExploitController.java  # attacker: publishes ObjectMessage(gadget) to the queue
    โ””โ”€โ”€ resources/
        โ””โ”€โ”€ application.properties
```

> In a real attack the serialized bytes are produced offline by the attacker (e.g. with **ysoserial**);
> only the **victim** needs the gadget chain on its classpath. This PoC builds the gadget in-process for
> convenience, which is why the JVM runs with `--add-opens java.base/java.util=ALL-UNNAMED` โ€” a
> gadget-construction detail, unrelated to the vulnerability.

## Prerequisites

- Java 17+ and Maven 3.8+
- Docker (runs the broker and the app)

## Reproduction Steps

### Step 1: Build and start everything

```bash
mvn clean package -DskipTests
docker compose up -d --build
```

This starts an Artemis broker (`quay.io/artemiscloud/activemq-artemis-broker`) and the reproducer app,
which connects to it over OpenWire.

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

```bash
curl -s http://localhost:8080/exploit/attack
# -> ObjectMessage published to queue 'evil'.
#    camel-jms consumer called ObjectMessage.getObject() -> deserialization.
#
#    >>> RCE proof โ€” /tmp/pwned exists: true
```

### Step 3: Verify

```bash
docker exec cve-2026-40860 ls -la /tmp/pwned
```

### Cleanup

```bash
docker compose down
```

## Attack Vectors

Any Camel JMS **consumer** (`camel-jms`, `camel-sjms`, `camel-sjms2`, `camel-amqp`, `camel-activemq`,
`camel-activemq6`) reading from a destination an attacker can publish to โ€” a shared broker, a topic with
open producers, a queue fed by an untrusted upstream โ€” with `mapJmsMessage=true` (the default).

## Exploit Conditions

1. A Camel JMS consumer with `mapJmsMessage=true` (default).
2. The attacker can enqueue an `ObjectMessage` to the consumed destination.
3. The JMS provider deserializes the payload (e.g. ActiveMQ `trustAllPackages=true`, or a provider without
   a restrictive filter).
4. **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**, **and** constrain deserialization end-to-end:

- Set a JVM-wide allow-list: `-Djdk.serialFilter=java.**;org.apache.camel.**;!*` (or the endpoint's new
  `deserializationFilter` option).
- Configure the **JMS provider's own** deserialization filter (e.g. ActiveMQ `trustedPackages`, do **not**
  use `trustAllPackages=true`).

## Mitigation

Until upgrading:

1. Prefer non-`ObjectMessage` payloads; set `mapJmsMessage=false` where the raw message is acceptable.
2. Lock down the JMS provider's trusted packages; never `trustAllPackages=true` on untrusted destinations.
3. Apply `-Djdk.serialFilter`.
4. **Remove gadget libraries** from the classpath (upgrade/remove commons-collections 3.x and similar).

## 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.