
Запускаемый proof-of-concept на Spring Boot, воспроизводящий CVE-2026-88900 — уязвимость небезопасной десериализации Java в camel-jgroups, — демонстрирующий поведение уязвимой и исправленной версий.
Запускаемый воспроизводитель proof-of-concept для уязвимости Apache Camel, при которой потребитель jgroups
выполнял Java-десериализацию сообщений кластера без какого-либо фильтра. JGroupsEndpoint.createExchange(Message) — вызываемый для каждого
сообщения, получаемого потребителем, — устанавливал тело exchange из org.jgroups.Message.getObject(). Для ObjectMessage
(тип, который отправляет продюсер Camel jgroups) JGroups выполняет Java-десериализацию полезной нагрузки через ObjectInputStream по мере
поступления сообщения, а getObject() возвращает результат. Никакой java.io.ObjectInputFilter не применялся, поэтому любой
сериализуемый класс в classpath приложения, полученный из кластера, инстанцировался и его колбэки десериализации
выполнялись — удалённое выполнение кода при наличии пригодной цепочки гаджетов. При стандартном стеке new JChannel()
(UDP multicast, без AUTH, без шифрования) любой хост, имеющий доступ к кластеру, может отправить такое сообщение без
учётных данных (CWE-502).
Только Spring Boot. Этот воспроизводитель содержит единственный модуль Camel Spring Boot. У
camel-jgroupsнет расширенияcamel-quarkus-jgroups, поэтому аналога для Quarkus для воспроизведения нет. Модуль Spring Boot демонстрирует как уязвимое, так и исправленное поведение.
| Среда выполнения | Каталог | Стек |
|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-jgroups 4.22.0 (уязвимая; исправлено в 4.22.1) |
Безвредный объект атакующего — com.example.Marker, обычный класс приложения, которого нет в списке разрешённых
по умолчанию в исправлении (java.**, javax.**, org.apache.camel.**), — сериализуется в сетевую форму JGroups и подаётся в
реальный JGroupsEndpoint.createExchange(...), который читает его через Message.getObject() (тот же вызов, который потребитель делает
для каждого полученного сообщения). Канал или multicast не нужны, поэтому проверка детерминирована. Marker.readObject
переключает флаг, показывая, что колбэк десериализации выполняется — реальная цепочка гаджетов выполнила бы вредоносный код в этой самой
точке; этот воспроизводитель не содержит гаджетов.
com.example.Marker, и createExchange выбрасывает
JGroupsException; объект никогда не достигает маршрута.Честная оговорка (как указано в рекомендации): проверка класса в 4.22.1 / 4.18.5 выполняется после того, как JGroups десериализовал полезную нагрузку, поэтому колбэк
readObjectвсё равно выполняется и в исправленной сборке — это эшелонированная защита. Чтобы остановить код, выполняющийся во время десериализации, необходимо также задать JVM-параметр-Djdk.serialFilterи защитить канал с помощьюAUTH+ шифрования; 4.23.0 дополнительно отказывается запускать потребителя, если один из этих механизмов контроля не настроен. Этот воспроизводитель показывает разницу в проверке классов; флаг выполнения колбэка делает оговорку наглядной.
cd camel-spring-boot
mvn clean package
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack # affected: Marker deserialized + routed; >>> PROVEN
docker compose down
# Patched control
mvn clean package -Dcamel.version=4.22.1
java -jar target/cve-2026-88900-jgroups-deserialization-0.0.1-SNAPSHOT.jar &
curl -s http://localhost:8080/exploit/attack # fixed: JGroupsException rejects com.example.Marker; >>> Not exploited
| Свойство | Значение |
|---|---|
| Компонент | camel-jgroups (JGroupsEndpoint.createExchange) |
| CWE | CWE-502 (Десериализация недоверенных данных) |
| Критичность | ВЫСОКАЯ |
| Вектор атаки | Хост, способный достичь multicast-группы кластера / порта привязки, отправляет специально сформированный ObjectMessage; потребитель десериализует его без фильтра |
| Воздействие | Удалённое выполнение кода в процессе Camel при наличии цепочки гаджетов в classpath; в противном случае — произвольное создание экземпляров классов |
| Затронутые версии | С 4.0.0 до 4.18.5, с 4.19.0 до 4.22.1 |
| Исправленные версии | 4.18.5, 4.22.1, 4.23.0 |
| JIRA | CAMEL-24676, CAMEL-25223 |
| Сообщил | h1ei1 |
Рекомендация: https://camel.apache.org/security/CVE-2026-88900.html
JGroupsEndpoint теперь проверяет класс тела, возвращаемого
Message.getObject(), до маршрутизации обмена, через новую опцию deserializationFilter (синтаксис
jdk.serialFilter). Если она не задана, используется JVM-фильтр jdk.serialFilter, если он присутствует, иначе
применяется консервативный список разрешённых по умолчанию, допускающий java.**/javax.**/org.apache.camel.**,
запрещающий java.net.** и отклоняющий всё остальное; отклонённое сообщение передаётся в ExceptionHandler
потребителя и не маршрутизируется. В версии 4.23.0 (CAMEL-25223) потребитель также отказывается запускаться,
если не настроен механизм контроля, действующий до десериализации (JVM-фильтр, системное свойство
jgroups.deserialization.filter или канал с AUTH+шифрованием). acceptAllObjects=true восстанавливает
прежнее поведение и помечен как небезопасная настройка.
Задайте -Djdk.serialFilter на JVM, в которой работает потребитель (разрешив только те классы, которыми обмениваются
ваши маршруты в кластере), защитите канал с помощью AUTH и SYM_ENCRYPT/ASYM_ENCRYPT через опцию
channelProperties и не открывайте multicast-группу кластера или порт привязки для недоверенных сетей.
Этот репозиторий публикуется в образовательных и защитных целях: чтобы помочь пользователям Apache Camel понять уязвимость, проверить, затронуты ли они, и убедиться, что обновление её устраняет. Десериализуемый объект — это безвредный маркерный класс, определённый в этом репозитории; он не содержит цепочки гаджетов и не выполняет вредоносных действий. Не используйте этот материал против систем, которыми вы не владеете и которые не эксплуатируете.