本项目演示了 CVE-2026-43866,这是对 Apache Camel 的 camel-jms(以及 camel-sjms / JMS 系列)组件中 CVE-2026-40860 修复的一种绕过。CVE-2026-40860 为传入的 JMS ObjectMessage 负载添加了反序列化后的类白名单(java.**;javax.**;org.apache.camel.**;!*)。但是 org.apache.camel.support.DefaultExchangeHolder 位于白名单 org.apache.camel.** 命名空间中,因此顶层对象是 DefaultExchangeHolder 的 ObjectMessage 可以绕过检查。接收端随后对它调用 DefaultExchangeHolder.unmarshal(),无需要求 transferExchange —— 将 holder 的每个非空字段写入路由的 Exchange(body、IN/OUT 头、Exchange 属性、变量、Exchange id、异常)。因此,能够发布 ObjectMessage 的攻击者可以仅使用普遍受信任的 java.* 类型注入任意 Exchange 状态 —— 无需反序列化 gadget 链 —— 从而操纵路由、头、属性和错误处理。
安全公告:https://camel.apache.org/security/CVE-2026-43866.html
// JmsBinding.extractBodyFromJms(...) - affected 4.18.2
if (message instanceof ObjectMessage objectMessage) {
Object payload = objectMessage.getObject();
checkDeserializedClass(payload); // CVE-2026-40860 allow-list: java.**;javax.**;org.apache.camel.**;!*
if (payload instanceof DefaultExchangeHolder holder) { // <-- DefaultExchangeHolder is org.apache.camel.** -> passes
DefaultExchangeHolder.unmarshal(exchange, holder); // <-- writes forged state into the Exchange; NO transferExchange gate
Map<String, Object> jmsHeaders = extractHeadersFromJms(message, exchange);
exchange.getIn().getHeaders().putAll(jmsHeaders);
return exchange.getIn().getBody();
} else {
return payload;
}
}
这种不对称性在于:发送端对 ObjectMessage/transferExchange 的创建进行了限制,但接收端会对反序列化得到的任何 DefaultExchangeHolder 执行 unmarshal。修复(4.14.8 / 4.18.3 / 4.21.0)新增了一个 objectMessageEnabled 选项(security = "insecure:serialization",默认 false)——除非显式启用,否则传入的 ObjectMessage 根本不再被反序列化,因此伪造的 holder 永远无法到达 unmarshal()。(对于依赖 ObjectMessage / transferExchange 的路由来说,这是一个破坏性变更。)
JMS 提供方的白名单也无济于事。 此 PoC 为 ActiveMQ 客户端配置了一个现实且严格受限的
trustedPackages = [java, javax, org.apache.camel]—— 其中org.apache.camel条目正是使用合法transferExchange的部署所必须信任的。伪造的 holder 依然能通过,因为它本身就是一个DefaultExchangeHolder,其字段全部是受信任的java.*类型,与合法的 holder 无法区分。
from("jms:queue:cve") // mapJmsMessage defaults to true; transferExchange NOT set
.process(exchange -> { /* observes the injected body / headers / properties */ });
受害方是 Camel JMS 消费者。攻击者是任何可以向该队列发布的生产者。两者都与 Docker 中真实的 Apache ActiveMQ Artemis 代理通信。
CVE-2026-43866/
├── pom.xml # camel-jms 4.18.2 + activemq-client 6.2.4 (NO gadget library)
├── Dockerfile # runs the app (no --add-opens; no gadget)
├── docker-compose.yml # Artemis broker (quay.io) + the reproducer app
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── JmsConfig.java # OpenWire ConnectionFactory (trustedPackages incl. org.apache.camel) + jms component
│ ├── VictimRoute.java # victim: from("jms:queue:cve"); records what the route observed
│ ├── CapturedState.java
│ ├── ForgedHolderFactory.java # builds a DefaultExchangeHolder via the public marshal() API
│ └── ExploitController.java # attacker: publishes the forged holder as an ObjectMessage
└── resources/
└── application.properties
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
# -> Published a forged DefaultExchangeHolder as a JMS ObjectMessage to queue 'cve'.
# ...
# body = INJECTED-BODY-... (injected: true)
# header = pwned-header-... (injected: true)
# property = pwned-property-... (injected: true)
#
# >>> Exchange-state injection proof — attacker controlled body+header+property: true
该路由运行时带有它从未设置过的 body、header 和 property —— 全部由攻击者伪造的 holder 提供。
docker compose down
任何启用了 mapJmsMessage=true(默认值)的 Camel JMS 消费者(camel-jms、camel-sjms、camel-sjms2、camel-amqp、camel-activemq、camel-activemq6),且从攻击者可以发布消息的目标读取消息。消费者上无需启用 transferExchange。
mapJmsMessage=true(默认值)。DefaultExchangeHolder 的 ObjectMessage 入队。transferExchange 的部署而言,这意味着提供方已经信任 org.apache.camel。无需任何 gadget 库。升级到 4.14.8 / 4.18.3 / 4.21.0(CAMEL-23373 / CAMEL-23409)。通过新的 objectMessageEnabled 选项,JMS ObjectMessage 处理默认被禁用;仅当目标只由受信任的生产者提供消息时才启用它。
在升级之前:
ObjectMessage body 的 JMS 消费者暴露给不可信网络。DefaultExchangeHolder)。本复现工具仅用于安全研究和授权测试,针对的是已公开披露并已修复的漏洞。未经明确许可,请勿将其用于任何系统。
| 属性 | 值 |
|---|
| 组件 | camel-jms(+ camel-sjms、camel-sjms2、camel-amqp、camel-activemq、camel-activemq6) |
| 受影响类 | org.apache.camel.component.jms.JmsBinding#extractBodyFromJms → DefaultExchangeHolder.unmarshal |
| CWE | CWE-502(不可信数据反序列化)+ CWE-20(输入验证不当) |
| 影响 | Exchange 状态注入:攻击者可控的 body、headers、properties、variables、exception |
| 性质 | 对 CVE-2026-40860 类过滤修复的绕过(并非该修复本身的缺陷) |
| 受影响版本 | 从 3.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-23373 (jms),CAMEL-23409 (sjms) |
| 报告者 | gaorenyusi |