Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-40860 — Reproducer for CVE-2026-40860 — Apache Camel camel-jms/sjms/amqp JMS ObjectMessage unsafe deserialization (RCE) | Kitploit
Tools/GitHubGitHub/oscerd/cve-2026-40860
Vulnerability AnalysisCode AnalysisExploitationWeb Application ExploitationPenetration TestingLearning & EducationBinary ExploitationLabs & Practice
GitHuboscerd/cve-2026-40860

CVE-2026-40860

Reproducer for CVE-2026-40860 — Apache Camel camel-jms/sjms/amqp JMS ObjectMessage unsafe deserialization (RCE)

View Repository
2 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

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 , class allow-list or deny-list. Because this runs whenever (the default) and Camel is a JMS , an attacker able to publish a crafted to a consumed queue/topic can achieve when a gadget chain is on the classpath.

no ObjectInputFilter
mapJmsMessage=true
consumer
ObjectMessage
remote code execution

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

Vulnerability Summary

PropertyValue
Componentscamel-jms (+ camel-sjms, camel-sjms2, camel-amqp, camel-activemq, camel-activemq6)
Affected Classorg.apache.camel.component.jms.JmsBinding#extractBodyFromJms → jakarta.jms.ObjectMessage#getObject()
CWECWE-502: Deserialization of Untrusted Data
ImpactRemote Code Execution (RCE)
TriggerCamel JMS consumer + mapJmsMessage=true (default) + an ObjectMessage the attacker can enqueue
Affected VersionsFrom 3.0.0 before 4.14.7, from 4.15.0 before 4.18.2, from 4.19.0 before 4.20.0
Fixed Versions4.14.7, 4.18.2, 4.20.0
JIRACAMEL-23321
ReporterVenkatraman Kumar (Securin)

Technical Details

root@kitploit:~
// JmsBinding.extractBodyFromJms(Exchange, Message) - affected version
if (message instanceof ObjectMessage objectMessage) {
    Object payload = objectMessage.getObject();   // <-- deserializes with no ObjectInputFilter
    if (payload instanceof DefaultExchangeHolder holder) {
        ...
    }
    return payload;
}

getObject() runs the JMS provider's ObjectInputStream.readObject() over the message body. Camel adds no class filtering of its own, so a gadget chain on the classpath executes during deserialization.

What the fix does (and its limits)

The fix (4.14.7 / 4.18.2 / 4.20.0) adds a default ObjectInputFilter allow-list (java.**;javax.**;org.apache.camel.**;!*), customisable via the new deserializationFilter endpoint option or the JVM-wide -Djdk.serialFilter. Note Camel's own commit message for the fix:

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

root@kitploit:~
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.

root@kitploit:~
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

root@kitploit:~
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)

root@kitploit:~
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

root@kitploit:~
docker exec cve-2026-40860 ls -la /tmp/pwned

Cleanup

root@kitploit:~
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.

Download Tool