
Рабочий воспроизводитель proof-of-concept для CVE-2026-85312, демонстрирующий перехват саги Apache Camel через заголовок Long-Running-Action в Spring Boot и Quarkus.
Long-Running-ActionЗапускаемый воспроизводитель proof-of-concept для уязвимости Apache Camel, при которой SagaProcessor в camel-core выбирал
координатор saga из заголовка сообщения Long-Running-Action в каждом exchange. Это имя заголовка не несёт префикса
Camel, поэтому оно находится вне пространства имён, которое отсекают фильтры заголовков потребителя — внешний отправитель мог указать
его во входящем сообщении и тем самым задать saga, к которой присоединяется его exchange, привязав свой запрос к длительно
выполняемому действию, запущенному кем-то другим (или связав компенсацию с действием, которое он не инициировал). Подверженность
ограничена развёртываниями, использующими saga, но там, где она применима, отправитель контролирует, к какой saga принадлежит exchange
(CWE-20).
| Среда выполнения | Каталог | Стек |
|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-spring-boot 4.22.0 (уязвим; исправлено в 4.22.1) |
| Camel Quarkus | camel-quarkus/ | Quarkus 3.39.0 + camel-quarkus-saga (Camel 4.22.0, уязвим; исправленный контроль CQ 3.40.0 / Camel 4.22.1) |
Оба модуля демонстрируют уязвимое и исправленное поведение на реальном SagaProcessor из camel-core.
Драйвер повторяет собственный регрессионный тест исправления (SagaHeaderCannotSelectCoordinatorTest). Он строит маршрут saga
from("direct:…").saga().propagation(MANDATORY) на основе in-memory сервиса saga, который записывает каждый id, который у него
запрашивают для разрешения, затем отправляет один exchange с входящим заголовком Long-Running-Action = a-saga-id-from-the-wire
— id, который внешний отправитель поместил бы в сообщение. Оракул — это просто какие id saga достигают сервиса:
a-saga-id-from-the-wire, переданный в сообщении, ищется
— сообщение выбрало координатор.В обеих сборках exchange с MANDATORY в конечном итоге завершается неудачей (нет реальной saga, к которой можно присоединиться) — уязвимость не в
неудаче, а в том, что выбранный атакующим id вообще использовался для выбора координатора, поэтому оракул следит за
поиском, а не за результатом.
# Camel Spring Boot
cd camel-spring-boot
mvn clean package
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack # affected: wire id looked up = true; >>> PROVEN
docker compose down
# Patched control
mvn clean package -Dcamel.version=4.22.1
java -jar target/cve-2026-85312-saga-header-hijack-0.0.1-SNAPSHOT.jar &
curl -s http://localhost:8080/exploit/attack # fixed: wire id looked up = false; >>> Not exploited
# Camel Quarkus
cd camel-quarkus
mvn clean package
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack # affected (Camel 4.22.0): wire id looked up = true
docker compose down
# Patched control: CQ 3.40.0 ships Camel 4.22.1
mvn clean package -Dcamel-quarkus.version=3.40.0 -Dquarkus.platform.version=3.40.0
java -jar target/quarkus-app/quarkus-run.jar &
curl -s http://localhost:8080/exploit/attack # fixed: wire id looked up = false
| Свойство | Значение |
|---|---|
| Компонент | camel-core (SagaProcessor.getCurrentSagaCoordinator) |
| CWE | CWE-20 (Некорректная проверка входных данных) |
| Критичность | MEDIUM |
| Вектор атаки | Внешний отправитель передаёт заголовок Long-Running-Action без префикса во входящем сообщении для маршрута, использующего EIP saga |
| Воздействие | Отправитель задаёт сагу, к которой присоединяется обмен — привязываясь к длительной операции другой стороны или вызывая неверную ассоциацию компенсации |
| Затронутые версии | С 4.0.0 до 4.18.5, с 4.19.0 до 4.22.1 |
| Исправленные версии | 4.18.5, 4.22.1, 4.23.0 |
| JIRA | CAMEL-24449 |
| Благодарность | Claude Security Scan Tool |
Рекомендация: https://camel.apache.org/security/CVE-2026-85312.html
Затронутый модуль Quarkus собран на CQ 3.39.0 (Camel 4.22.0). Исправленный элемент управления — CQ 3.40.0 (Camel 4.22.1).
SagaProcessor теперь обращается к заголовку Long-Running-Action только тогда,
когда сервис saga объявляет, что участвует в таком протоколе, через новый метод
CamelSagaService.isLongRunningActionHeaderSupported() (по умолчанию false; сервис LRA переопределяет его на true).
Внутреннее состояние обмена — которое сохраняется после removeHeaders("*") — остаётся обычным носителем идентификатора saga, поэтому сообщение
больше не может выбрать координатор для сервиса, который не запускает внешний координатор.
Удаляйте заголовок на границе доверия с помощью removeHeaders("Long-Running-Action") на каждом потребителе, который принимает
сообщения от недоверенного отправителя.
Этот репозиторий публикуется в образовательных и защитных целях: чтобы помочь пользователям Apache Camel понять уязвимость, проверить, затронуты ли они, и убедиться, что обновление её устраняет. Демонстрация запускает маршрут saga внутри процесса с сервисом saga в памяти; идентификатор saga «атакующего» — это безвредная строка-заполнитель. Не используйте этот материал против систем, которыми вы не владеете и которые не эксплуатируете.