
Reproducer per CVE-2026-43866 — Apache Camel camel-jms DefaultExchangeHolder contraffatto bypass del filtro di deserializzazione CVE-2026-40860 (iniezione dello stato Exchange)
Questo progetto dimostra CVE-2026-43866, un bypass della correzione di CVE-2026-40860 nei componenti camel-jms (e camel-sjms / famiglia JMS) di Apache Camel. CVE-2026-40860 ha aggiunto una allow-list di classi post-deserializzazione (java.**;javax.**;org.apache.camel.**;!*) ai payload JMS ObjectMessage in ingresso. Ma org.apache.camel.support.DefaultExchangeHolder si trova nel namespace org.apache.camel.** incluso nella allow-list, quindi un ObjectMessage il cui oggetto di primo livello è un DefaultExchangeHolder supera il controllo. Il lato ricevente invoca quindi DefaultExchangeHolder.unmarshal() su di esso senza richiedere transferExchange — scrivendo ogni campo non nullo dell'holder nell'Exchange instradato (body, header IN/OUT, proprietà dell'exchange, variabili, exchange id, eccezione). Un attaccante in grado di pubblicare un ObjectMessage può quindi iniettare stato arbitrario dell'Exchange utilizzando solo tipi java.* universalmente fidati — nessuna gadget chain di deserializzazione richiesta — per manipolare routing, header, proprietà e gestione degli errori.
Avviso di sicurezza: 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;
}
}
L'asimmetria: il lato mittente vincola la creazione di ObjectMessage/transferExchange, mentre il lato ricevente esegue l'unmarshal di qualsiasi DefaultExchangeHolder che deserializza. La correzione (4.14.8 / 4.18.3 / 4.21.0) aggiunge una nuova opzione objectMessageEnabled (security = "insecure:serialization", default false) — un ObjectMessage in ingresso non viene più deserializzato affatto a meno che non sia esplicitamente abilitato, quindi un holder forgiato non può mai raggiungere unmarshal(). (È una modifica che rompe la compatibilità per le route che si affidano a ObjectMessage / transferExchange.)
Una allow-list del provider JMS non aiuta. Questa PoC configura il client ActiveMQ con una
trustedPackages = [java, javax, org.apache.camel]realistica e restrittiva — la voceorg.apache.camelè esattamente ciò di cui un deployment che utilizza il legittimotransferExchangedeve fidarsi. L'holder forgiato supera comunque il controllo, perché è esso stesso unDefaultExchangeHolderi cui campi sono tutti tipijava.*fidati, indistinguibile da uno legittimo.
from("jms:queue:cve") // mapJmsMessage defaults to true; transferExchange NOT set
.process(exchange -> { /* observes the injected body / headers / properties */ });
La vittima è il consumer JMS di Camel. L'attaccante è qualsiasi producer che possa pubblicare sulla coda. Entrambi comunicano con un broker reale Apache ActiveMQ Artemis in Docker.
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
La route è stata eseguita con un body, un header e una proprietà che non aveva mai impostato — tutti forniti dall'holder forgiato dall'attaccante.
docker compose down
Qualsiasi consumer JMS di Camel (camel-jms, camel-sjms, camel-sjms2, camel-amqp, camel-activemq, camel-activemq6) con mapJmsMessage=true (il default), che legga da una destinazione su cui un attaccante può pubblicare. transferExchange non deve essere abilitato sul consumer.
mapJmsMessage=true (default), su una versione interessata.ObjectMessage il cui payload è un DefaultExchangeHolder.transferExchange, significa che il provider si fida già di org.apache.camel. Non è richiesta alcuna libreria di gadget.Aggiornare a 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23373 / CAMEL-23409). La gestione degli ObjectMessage JMS è disabilitata per impostazione predefinita tramite la nuova opzione objectMessageEnabled; abilitarla solo su destinazioni alimentate esclusivamente da producer fidati.
In attesa dell'aggiornamento:
ObjectMessage verso reti non affidabili.DefaultExchangeHolder).Questo riproduttore è fornito esclusivamente per ricerca sulla sicurezza e test autorizzati, per una vulnerabilità divulgata pubblicamente e corretta. Non utilizzarlo contro sistemi senza esplicita autorizzazione.
| Proprietà | Valore |
|---|
| Componenti | camel-jms (+ camel-sjms, camel-sjms2, camel-amqp, camel-activemq, camel-activemq6) |
| Classe interessata | org.apache.camel.component.jms.JmsBinding#extractBodyFromJms → DefaultExchangeHolder.unmarshal |
| CWE | CWE-502 (Deserializzazione di dati non attendibili) + CWE-20 (Convalida errata dell'input) |
| Impatto | Iniezione dello stato dell'Exchange: body, header, proprietà, variabili ed eccezione controllati dall'attaccante |
| Natura | Bypass della correzione del filtro classi di CVE-2026-40860 (non un difetto della stessa) |
| Versioni interessate | Dalla 3.0.0 alla 4.14.8 esclusa, dalla 4.15.0 alla 4.18.3 esclusa, dalla 4.19.0 alla 4.21.0 esclusa |
| Versioni corrette | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23373 (jms), CAMEL-23409 (sjms) |
| Reporter | gaorenyusi |