
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 メッセージヘッダーにコピーします。そのうちの 2 つ — 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
あるトピックから消費して別のトピックに再パブリッシュするルート(一般的な監査・転送・ファンアウトパターン)において、サブスクライブ 中のトピックにパブリッシュできる攻撃者は、CloudEvent の pubsubName/topic を設定し、再パブリッシュされるメッセージを任意の Dapr pub/sub コンポーネント + トピックにリダイレクト できます。これにより、ペイロードを攻撃者が到達可能なブローカーに外部送信したり、意図したルーティング/ACL を迂回したりできます。これは confused deputy(混乱した代理人) です:アプリは自身の Dapr 資格情報で、攻撃者が選んだ宛先に再パブリッシュしてしまいます。
この PoC は、その影響を メッセージリダイレクト / データ外部送信(CWE-441、CWE-20 に由来) として実証します。
アドバイザリ: https://camel.apache.org/security/CVE-2026-49086.html
この修正により、コンシューマーは 2 つのルーティングヘッダー(
CamelDaprPubSubName/CamelDaprTopic)を設定しなくなります。その他の CloudEvent メタデータヘッダーは変更されません。これにより、プロデューサーは常にエンドポイントに設定された pub/sub + トピックを使用します。(カタログの一貫性のためDaprHeaderFilterStrategyも追加されましたが、実質的な修正はルーティングヘッダーの変更です。)
この脆弱性は完全に Camel 側にあります — コンシューマーが CloudEvent.pubsubName/topic をルーティングヘッダーにコピーすること、そしてプロデューサーがそれらのヘッダーを優先することです。Dapr サイドカーは単なる転送手段にすぎません。この再現コードは モック Dapr SDK クライアント(client=#mockClient、previewClient=#mockPreview)を注入するため、本物の DaprPubSubConsumer と DaprPubSubHandler がサイドカーなしでそのまま実行されます。モック preview クライアントはサブスクリプションリスナーを捕捉し、モッククライアントはパブリッシュ先を記録します。そして攻撃者ドライバーは、捕捉されたリスナーに偽造 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(意図しないプロキシ / Confused Deputy(混乱した代理人)) |
| 影響 | 再パブリッシュされたメッセージを任意の Dapr pub/sub コンポーネント + トピックにリダイレクト(外部送信 / ルーティングおよび ACL の迂回) |
| 前提条件 | ルートが dapr:pubSub トピックから消費し、dapr:pubSub プロデューサー経由で再パブリッシュする;攻撃者がサブスクライブ中のトピックにパブリッシュできること |
| 影響を受けるバージョン | 4.12.0 から 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 |