
Воспроизведение для CVE-2026-40860 — небезопасная десериализация JMS ObjectMessage в Apache Camel camel-jms/sjms/amqp (RCE)
Этот проект демонстрирует уязвимость десериализации Java в компоненте camel-jms Apache Camel
(и, транзитивно, camel-sjms, camel-sjms2, camel-amqp, camel-activemq, camel-activemq6),
отслеживаемую как CVE-2026-40860. JmsBinding.extractBodyFromJms() десериализует полезную нагрузку
входящего JMS ObjectMessage через ObjectMessage.getObject() без ObjectInputFilter, без белого
или чёрного списка классов. Поскольку это происходит всегда, когда mapJmsMessage=true (значение по
умолчанию), а Camel является JMS потребителем, злоумышленник, способный опубликовать сформированный
ObjectMessage в потребляемую очередь/топик, может достичь удалённого выполнения кода, если на
classpath присутствует цепочка гаджетов.
Уведомление: https://camel.apache.org/security/CVE-2026-40860.html
| Свойство | Значение |
|---|---|
| Компоненты | camel-jms (+ camel-sjms, camel-sjms2, camel-amqp, camel-activemq, camel-activemq6) |
| Затрагиваемый класс | org.apache.camel.component.jms.JmsBinding#extractBodyFromJms → jakarta.jms.ObjectMessage#getObject() |
| CWE | CWE-502: Десериализация ненадёжных данных |
| Влияние | Удалённое выполнение кода (RCE) |
| Триггер | Потребитель JMS Camel + mapJmsMessage=true (по умолчанию) + ObjectMessage, который злоумышленник может поставить в очередь |
| Затрагиваемые версии | Начиная с 3.0.0 до 4.14.7, с 4.15.0 до 4.18.2, с 4.19.0 до 4.20.0 |
| Исправленные версии | 4.14.7, 4.18.2, 4.20.0 |
| JIRA | CAMEL-23321 |
| Автор отчёта | Venkatraman Kumar (Securin) |
// JmsBinding.extractBodyFromJms(Exchange, Message) - affected version
if (message instanceof ObjectMessage objectMessage) {
Object payload = objectMessage.getObject(); // <-- десериализует без ObjectInputFilter
if (payload instanceof DefaultExchangeHolder holder) {
...
}
return payload;
}
getObject() запускает ObjectInputStream.readObject() JMS-провайдера над телом сообщения. Camel не
добавляет собственной фильтрации классов, поэтому цепочка гаджетов на classpath выполняется во время
десериализации.
Исправление (4.14.7 / 4.18.2 / 4.20.0) добавляет белый список ObjectInputFilter по умолчанию
(java.**;javax.**;org.apache.camel.**;!*), настраиваемый через новый параметр конечной точки
deserializationFilter или общеjvm-ный -Djdk.serialFilter. Обратите внимание на собственное
сообщение коммита Camel об исправлении:
эта проверка выполняется после того, как JMS-провайдер уже десериализовал полезную нагрузку. Она предотвращает распространение неожиданных классов в маршрут, но сама по себе не может остановить цепочки гаджетов, чей
readObject()срабатывает внутриObjectInputStreamпровайдера. Полная защита требует настройки собственного фильтра десериализации JMS-провайдера и/или общеjvm-ного-Djdk.serialFilter.
Таким образом, полная защита = обновить Camel + ограничить провайдер/JVM-фильтр. Этот PoC использует
клиент ActiveMQ с trustAllPackages=true (часто встречающаяся реальная настройка), поэтому провайдер
десериализует полезную нагрузку; на уязвимой версии Camel больше ничего не мешает.
from("jms:queue:evil") // mapJmsMessage по умолчанию true
.log("Consumed: ${body.class.name}");
Простое получение ObjectMessage запускает десериализацию — тело маршрута не имеет значения.
Жертва — это потребитель Camel JMS. Злоумышленник — любой производитель, способный публиковать в очередь. Оба общаются с реальным брокером Apache ActiveMQ Artemis, запущенным в Docker.
CVE-2026-40860/
├── pom.xml # camel-jms 4.18.1 + activemq-client 6.2.4 + commons-collections 3.2.1 (гаджет)
├── Dockerfile # запускает приложение (--add-opens только для сборки гаджета)
├── docker-compose.yml # брокер Artemis (quay.io) + приложение-воспроизводитель
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── JmsConfig.java # OpenWire ConnectionFactory (trustAllPackages=true) + jms компонент
│ ├── VictimRoute.java # жертва: from("jms:queue:evil")
│ ├── Gadget.java # гаджет CommonsCollections6, срабатывает во время getObject()
│ └── ExploitController.java # злоумышленник: публикует ObjectMessage(гаджет) в очередь
└── resources/
└── application.properties
В реальной атаке сериализованные байты создаются офлайн злоумышленником (например, с помощью ysoserial); только жертве нужна цепочка гаджетов на своём classpath. Для удобства этот PoC строит гаджет внутри процесса, поэтому JVM запускается с
--add-opens java.base/java.util=ALL-UNNAMED— это деталь конструирования гаджета, не связанная с уязвимостью.
mvn clean package -DskipTests
docker compose up -d --build
Это запускает брокер Artemis (quay.io/artemiscloud/activemq-artemis-broker) и приложение-воспроизводитель,
которое подключается к нему по OpenWire.
curl -s http://localhost:8080/exploit/attack
# -> ObjectMessage опубликован в очередь 'evil'.
# потребитель camel-jms вызвал ObjectMessage.getObject() -> десериализация.
#
# >>> Доказательство RCE — /tmp/pwned существует: true
docker exec cve-2026-40860 ls -la /tmp/pwned
docker compose down
Любой потребитель Camel JMS (camel-jms, camel-sjms, camel-sjms2, camel-amqp, camel-activemq,
camel-activemq6), читающий из места назначения, куда злоумышленник может публиковать — общий брокер, топик
с открытыми производителями, очередь, питаемая ненадёжным вышестоящим компонентом — с
mapJmsMessage=true (по умолчанию).
mapJmsMessage=true (по умолчанию).ObjectMessage в потребляемое место назначения.trustAllPackages=true, или провайдер
без ограничительного фильтра).commons-collections:3.2.1).Обновитесь до 4.14.7 / 4.18.2 / 4.20.0 и ограничьте десериализацию от начала до конца:
-Djdk.serialFilter=java.**;org.apache.camel.**;!* (или новый
параметр конечной точки deserializationFilter).trustedPackages ActiveMQ,
не используйте trustAllPackages=true).До обновления:
ObjectMessage; установите mapJmsMessage=false там, где
сырое сообщение приемлемо.trustAllPackages=true на
ненадёжных местах назначения.-Djdk.serialFilter.Этот воспроизводитель предоставляется только для исследования безопасности и авторизованного тестирования для публично раскрытой и исправленной уязвимости. Не используйте его против систем без явного разрешения.