
Рабочий proof-of-concept репродьюсер для CVE-2026-78162, демонстрирующий неаутентифицированную десериализацию Java в Apache Camel camel-hazelcast в Spring Boot и Quarkus.
Запускаемый воспроизводитель proof-of-concept для уязвимости Apache Camel, при которой camel-hazelcast создавал экземпляры Hazelcast
без JavaSerializationFilterConfig на двух путях конфигурации, до которых не доходило усиление безопасности из CVE-2026-43865.
На этих путях член/клиент Hazelcast, созданный Camel, десериализует значения, прочитанные из кластера,
без каких-либо ограничений на классы, поэтому злоумышленник, способный публиковать данные в кластер, может добиться десериализации
выбранного им сериализованного Java-объекта внутри слоя сериализации Hazelcast — удалённое выполнение кода (CWE-502). Кластеры Hazelcast
по умолчанию не имеют ни аутентификации, ни TLS.
Этот воспроизводитель использует наиболее очевидный из двух путей: ReplicatedHazelcastAggregationRepository, который переопределяет
doStart() без вызова super.doStart() и в уязвимой сборке запускает собственный локальный член без применения
фильтра по умолчанию. (Парный путь, HazelcastDefaultComponent#getOrCreateHzClientInstance() для
hazelcastMode=client, покрывается тем же исправлением.)
| Среда выполнения | Каталог | Стек |
|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-hazelcast 4.22.0 (уязвим; исправлено в 4.22.1) |
| Camel Quarkus | camel-quarkus/ | Quarkus 3.29.0 + camel-quarkus-hazelcast 3.29.0 (Camel 4.15.0, уязвим) |
Контроль «исправлено против уязвимо»: исправление поставляется в Camel 4.18.5 / 4.22.1 / 4.23.0. Модуль Spring Boot может запускать как уязвимую сборку (4.22.0), так и исправленную (4.22.1), поэтому он демонстрирует и исправленное поведение. Ни один выпущенный Camel Quarkus пока не включает исправленный Camel (последний, 3.29.0, основан на Camel 4.15.0), поэтому модуль Quarkus демонстрирует только уязвимый случай.
Приложение запускает маршрут Camel, опирающийся на ReplicatedHazelcastAggregationRepository без внешне предоставленного
HazelcastInstance, поэтому репозиторий запускает собственный локальный член Hazelcast (кластер по умолчанию dev, порт 5701). В
уязвимой сборке у этого члена нет JavaSerializationFilterConfig.
Затем клиент-злоумышленник присоединяется к кластеру и публикует сериализованный объект в резервную ReplicatedMap. Клиент
Hazelcast только отправляет байты — он не хранит и не десериализует значения карты — поэтому любая сработавшая десериализация
приписывается члену-жертве. Публикуемый объект — намеренно безвредный маркер,
com.example.PwnMarker: он не несёт цепочки гаджетов и не выполняет команд, он лишь фиксирует (через глобальный флаг JVM), что
его readObject выполнился. Настоящий злоумышленник опубликовал бы здесь известный класс-гаджет для RCE — доказать, что
класс вообще был десериализован, достаточно.
Поскольку фильтр по умолчанию из исправления представляет собой белый список префиксов имён классов java., javax. и org.apache.camel.,
com.example.PwnMarker — идеальный оракул:
PwnMarker десериализуется, readObject выполняется на члене-жертве → ДОКАЗАНО.com.example.PwnMarker до readObject → java.lang.SecurityException: Resolving class com.example.PwnMarker is not allowed → не эксплуатируется.cd camel-spring-boot
mvn clean package
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
Ожидаемый вывод на уязвимой сборке:
=== CVE-2026-78162 — camel-hazelcast ReplicatedHazelcastAggregationRepository ===
=== missing JavaSerializationFilterConfig on the Camel-built member ===
Attacker client joined the victim cluster 'dev' at 127.0.0.1:5701.
Attacker published a com.example.PwnMarker into ReplicatedMap 'aggregation'.
Result:
>>> PROVEN: the Camel-built Hazelcast member deserialized an attacker-supplied, non-whitelisted
>>> class (com.example.PwnMarker) with no JavaSerializationFilterConfig in effect — its readObject
>>> executed inside the victim. A real attacker would publish a gadget class here instead, for RCE.
>>> PwnMarker.readObject executed inside the victim member; tag=attacker-rce-marker; thread=hz.*.partition-operation.thread-1
| Свойство | Значение |
|---|---|
| Компонент | camel-hazelcast (camel-hazelcast-starter / camel-quarkus-hazelcast) |
| CWE | CWE-502 (Десериализация недоверенных данных) |
| Уровень серьёзности | MEDIUM |
| Вектор атаки | Злоумышленник, способный опубликовать в кластере Hazelcast, к которому подключён уязвимый экземпляр, — созданный Camel участник/клиент десериализует опубликованный объект без ограничений по классам |
| Воздействие | Удалённое выполнение кода внутри процесса Camel (через класс-гаджет) до того, как Camel обработает exchange |
| Уязвимые версии | С 4.0.0 до 4.18.5, с 4.19.0 до 4.22.1 |
| Исправленные версии | 4.18.5, 4.22.1, 4.23.0 |
| JIRA | CAMEL-24413, CAMEL-24420 |
| Благодарность | cattier из TCBS; Leon Zlobecki |
Рекомендация: https://camel.apache.org/security/CVE-2026-78162.html
HazelcastSerializationFilterHelper.applyDefault(...) получил перегрузку с ClientConfig и теперь вызывается на обоих
ранее непокрытых путях — ReplicatedHazelcastAggregationRepository#doStart() и
HazelcastDefaultComponent#getOrCreateHzClientInstance() — так что каждая конфигурация Hazelcast, которую Camel создаёт сам,
несёт стандартный JavaSerializationFilterConfig (белый список java. / javax. / org.apache.camel., чёрный список
java.net.). Предоставленные пользователем Config, ClientConfig или HazelcastInstance по-прежнему остаются нетронутыми. Эта рекомендация
является продолжением неполного исправления CVE-2026-43865.
Предоставьте явную конфигурацию Hazelcast с JavaSerializationFilterConfig или внедрите заранее созданный
HazelcastInstance (предоставленная пользователем конфигурация никогда не перезаписывается Camel); задайте общесистемное для JVM
свойство -Djdk.serialFilter=...; а также включите аутентификацию кластера Hazelcast и TLS.
Этот репозиторий публикуется в образовательных и защитных целях: чтобы помочь пользователям Apache Camel понять уязвимость, проверить, затронуты ли они, и убедиться, что обновление её устраняет. Полезная нагрузка представляет собой безвредный маркер, не выполняющий никакого кода. Не используйте этот материал против систем, которыми вы не владеете и не управляете.