
CVE-2026-40860 の再現コード — Apache Camel camel-jms/sjms/amqp JMS ObjectMessage の安全でないデシリアライゼーション (RCE)
このプロジェクトは、Apache Camel の camel-jms コンポーネント(および推移的に camel-sjms、camel-sjms2、camel-amqp、camel-activemq、camel-activemq6)における Java デシリアライゼーションの脆弱性 を実証するもので、CVE-2026-40860 として追跡されています。JmsBinding.extractBodyFromJms() は、受信した JMS ObjectMessage のペイロードを、ObjectMessage.getObject() 経由で ObjectInputFilter(クラス許可リストまたは拒否リスト)なし でデシリアライズします。この処理は (デフォルト)のときに常に実行され、Camel が JMS であるため、攻撃者が細工した を消費対象のキュー/トピックに公開できれば、ガジェットチェーンがクラスパス上にある場合に が可能になります。
mapJmsMessage=trueObjectMessage| Property | Value |
|---|---|
| コンポーネント | camel-jms (+ camel-sjms, camel-sjms2, camel-amqp, camel-activemq, camel-activemq6) |
| 影響を受けるクラス | org.apache.camel.component.jms.JmsBinding#extractBodyFromJms → jakarta.jms.ObjectMessage#getObject() |
| CWE | CWE-502: 信頼できないデータのデシリアライゼーション |
| 影響 | リモートコード実行 (RCE) |
| トリガー | Camel JMS コンシューマー + mapJmsMessage=true(デフォルト)+ 攻撃者がエンキューできる ObjectMessage |
| 影響を受けるバージョン | 3.0.0 以上 4.14.7 未満、4.15.0 以上 4.18.2 未満、4.19.0 以上 4.20.0 未満 |
| 修正済みバージョン | 4.14.7, 4.18.2, 4.20.0 |
| JIRA | CAMEL-23321 |
| 報告者 | Venkatraman Kumar (Securin) |
// JmsBinding.extractBodyFromJms(Exchange, Message) - affected version
if (message instanceof ObjectMessage objectMessage) {
Object payload = objectMessage.getObject(); // <-- deserializes with no ObjectInputFilter
if (payload instanceof DefaultExchangeHolder holder) {
...
}
return payload;
}
getObject() は、JMS プロバイダーの ObjectInputStream.readObject() をメッセージ本文に対して実行します。Camel は独自のクラスフィルタリングを一切追加しないため、クラスパス上のガジェットチェーンがデシリアライゼーション中に実行されます。
修正(4.14.7 / 4.18.2 / 4.20.0)では、新しい deserializationFilter エンドポイントオプションまたは JVM 全体の -Djdk.serialFilter でカスタマイズ可能な、デフォルトの ObjectInputFilter 許可リスト(java.**;javax.**;org.apache.camel.**;!*)が追加されています。修正に関する Camel 自身のコミットメッセージには次のようにあります:
このチェックは、JMS プロバイダーがペイロードを既にデシリアライズした後に実行されます。予期しない クラスがルートに伝播するのを防ぎますが、それだけでは、
readObject()が プロバイダーのObjectInputStream内で発火するガジェットチェーンを阻止できません。完全な保護には、 JMS プロバイダー自身のデシリアライゼーションフィルターや JVM 全体の-Djdk.serialFilterの設定が必要です。
つまり、完全な保護 = Camel のアップグレード + プロバイダー / JVM フィルターの制限 です。この PoC は、trustAllPackages=true(実世界でよく見られる設定)の ActiveMQ クライアントを使用して、プロバイダーがペイロードをデシリアライズするようにしています。影響を受ける Camel バージョンでは、これを妨げるものは他にありません。
from("jms:queue:evil") // mapJmsMessage defaults to true
.log("Consumed: ${body.class.name}");
ObjectMessage を受信するだけでデシリアライゼーションがトリガーされます。ルートの本文は無関係です。
被害者 は Camel JMS コンシューマーです。攻撃者 はキューに公開できる任意のプロデューサーです。両者は Docker で動作する実物の Apache ActiveMQ Artemis ブローカーと通信します。
CVE-2026-40860/
├── pom.xml # camel-jms 4.18.1 + activemq-client 6.2.4 + commons-collections 3.2.1 (gadget)
├── Dockerfile # runs the app (--add-opens only to build the gadget)
├── docker-compose.yml # Artemis broker (quay.io) + the reproducer app
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── JmsConfig.java # OpenWire ConnectionFactory (trustAllPackages=true) + jms component
│ ├── VictimRoute.java # victim: from("jms:queue:evil")
│ ├── Gadget.java # CommonsCollections6 gadget, fires during getObject()
│ └── ExploitController.java # attacker: publishes ObjectMessage(gadget) to the queue
└── resources/
└── application.properties
実際の攻撃では、シリアライズされたバイト列は攻撃者によってオフラインで生成されます(例: ysoserial を使用)。ガジェットチェーンをクラスパスに持つ必要があるのは被害者だけです。この PoC は便宜上、ガジェットをプロセス内で構築するため、JVM は
--add-opens java.base/java.util=ALL-UNNAMEDで実行されます。これはガジェット構築上の詳細であり、脆弱性とは無関係です。
mvn clean package -DskipTests
docker compose up -d --build
これにより、Artemis ブローカー(quay.io/artemiscloud/activemq-artemis-broker)と再現アプリが起動し、アプリは OpenWire でブローカーに接続します。
curl -s http://localhost:8080/exploit/attack
# -> ObjectMessage published to queue 'evil'.
# camel-jms consumer called ObjectMessage.getObject() -> deserialization.
#
# >>> RCE proof — /tmp/pwned exists: true
docker exec cve-2026-40860 ls -la /tmp/pwned
docker compose down
攻撃者が公開先にメッセージを送信できる任意の Camel JMS コンシューマー(camel-jms、camel-sjms、camel-sjms2、camel-amqp、camel-activemq、camel-activemq6)が、mapJmsMessage=true(デフォルト)で宛先から読み取る場合、影響を受けます。具体例としては、共有ブローカー、プロデューサーがオープンなトピック、信頼されない上流から供給されるキューなどがあります。
mapJmsMessage=true(デフォルト)の Camel JMS コンシューマー。ObjectMessage をエンキューできる。trustAllPackages=true、または制限的フィルターを持たないプロバイダー)。commons-collections:3.2.1)。4.14.7 / 4.18.2 / 4.20.0 にアップグレードし、かつ デシリアライゼーションをエンドツーエンドで制限してください:
-Djdk.serialFilter=java.**;org.apache.camel.**;!*(またはエンドポイントの新しい deserializationFilter オプション)。trustedPackages。trustAllPackages=true は使用しない)。アップグレードまでの間:
ObjectMessage 以外のペイロードを優先する。生のメッセージで問題ない場合は mapJmsMessage=false に設定する。trustAllPackages=true にしない。-Djdk.serialFilter を適用する。この再現ツールは、セキュリティ研究および許可を得たテストのみを目的として提供されており、公開され修正済みの脆弱性を対象としています。明示的な許可なくシステムに対して使用しないでください。