
Reproductor de prueba de concepto ejecutable para CVE-2026-101259, que demuestra la divulgación de mensajes de error en consumidores de camel-coap de Apache Camel en Spring Boot y Quarkus, además de la verificación de la corrección.
Reproductor de prueba de concepto ejecutable para la vulnerabilidad de Apache Camel en la que, cuando el consumidor CoAP no podía
construir su respuesta una vez que la ruta había finalizado, CamelCoapResource capturaba la excepción resultante
y enviaba su mensaje de vuelta al cliente CoAP como carga útil de un 5.00 Internal Server Error:
} catch (Exception e) {
cexchange.respond(ResponseCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
| Runtime | Directorio | Stack |
|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-coap 4.22.1 |
| Camel Quarkus | camel-quarkus/ | Camel Quarkus 3.39.0 (Quarkus 3.39.0, Camel 4.22.0) |
El consumidor convierte el cuerpo del mensaje final en la carga útil byte[], y los encabezados CamelCoapMaxAge y
CamelCoapETag a sus tipos, después de que la ruta haya retornado — y por lo tanto fuera del
manejador de errores de la ruta. Un onException en la ruta no puede capturarlo, porque el fallo ocurre en el
consumidor, no en la ruta.
cd camel-spring-boot # or: cd camel-quarkus
mvn clean package
docker compose up -d --build
until [ "$(curl -s http://localhost:8080/exploit/ready)" = "Started" ]; do sleep 1; done
curl -s http://localhost:8080/exploit/attack
docker compose down
En una compilación afectada (idéntico en ambos runtimes):
1) Converting the body to the byte[] payload fails once the route has completed
CoAP GET coap://127.0.0.1:5683/reading
response code : 5.00 (INTERNAL_SERVER_ERROR)
response payload : Error during type conversion from type: com.example.FailingBackendStream to the
required type: byte[] with value com.example.FailingBackendStream@5eede7d7 due to
java.io.IOException: connection to prod-db.internal:5432 reset while streaming
sensor_readings for node edge-gateway-07.dc2.internal
2) The CamelCoapMaxAge header cannot be converted to its type
CoAP GET coap://127.0.0.1:5683/reading-maxage
response code : 5.00 (INTERNAL_SERVER_ERROR)
response payload : Error during type conversion from type: java.lang.String to the required type:
java.lang.Long with value not-a-number due to java.lang.NumberFormatException:
For input string: "not-a-number"
3) A route that simply fails
CoAP GET coap://127.0.0.1:5683/reading-failing
response code : 2.05 (CONTENT)
response payload : partially built response
What a remote CoAP client learned from these responses:
the backend host and port, out of the cause's message : true
class names of the cause : true
the source and target types of the conversion : true
the string form of the offending value : true
a failed route answered with a SUCCESS code : true
>>> PROVEN: ...
El mensaje de dicho fallo nombra la clase del valor que se está convirtiendo, lleva la forma de cadena
del valor y termina con el nombre de la clase y el mensaje de la causa subyacente — de modo que un cliente
CoAP remoto leía nombres de clase y de paquete, la forma de cadena del valor y lo que sea que lleve la causa,
que en la práctica puede incluir rutas, nombres de host y detalles de conexión de un backend. El consumidor
no tenía opción de suprimir esto, a diferencia de los consumidores HTTP, que ofrecen muteException para
ese propósito.
La sonda 3 es la segunda mitad del problema. La excepción lanzada por una ruta fallida no se enviaba en
absoluto: el consumidor no comprobaba si el intercambio había fallado, y respondía a un fallo de ruta con
2.05 Content y el cuerpo que el mensaje tuviera en ese momento — un código de éxito para una ruta fallida.
Una cosa que este reproductor tenía que acertar: un cuerpo para el que no existe convertidor no es suficiente.
getBody(byte[].class)devuelvenullen ese caso en lugar de lanzar una excepción, y el consumidor entonces responde2.05con una carga útil vacía — sin divulgación. La conversión tiene que fallar, no estar disponible, y por eso la sonda 1 usa un cuerpo de flujo que lanza una excepción a mitad de una lectura. La sonda de cabecera falla de la otra manera, mediante un valor con la forma incorrecta.
Alcanzar la divulgación requiere una ruta cuya respuesta completada un cliente remoto pueda hacer no convertible, lo cual depende de cómo esté escrita la ruta. Nada de esto está autenticado, y las peticiones GET de CoAP simples son todo lo que envía el cliente.
| Propiedad | Valor |
|---|---|
| Componente | camel-coap (CamelCoapResource) |
| CWE | CWE-209 (Generación de mensaje de error que contiene información sensible) |
| Gravedad | Media |
| Vector de ataque | Una petición CoAP a un consumidor cuya respuesta completada no puede construirse — un cuerpo que falla la conversión a byte[], o una cabecera CamelCoapMaxAge / CamelCoapETag que falla la conversión |
| Impacto | Un cliente CoAP remoto lee nombres de clase y de paquete, la forma de cadena del valor y el mensaje de la causa subyacente — en la práctica rutas, nombres de host y detalles de conexión del backend |
| Versiones afectadas | Desde 4.0.0 anterior a 4.18.5, desde 4.19.0 anterior a 4.22.2 |
| Versiones corregidas | 4.18.5, 4.22.2, 4.23.0 |
| JIRA | CAMEL-25087 |
| Crédito | Zhixi "Jace" Sun, investigador de seguridad independiente |
Aviso: https://camel.apache.org/security/CVE-2026-101259.html
El consumidor incorpora una opción muteException — tanto en los endpoints coap, coaps, coap+tcp como
coaps+tcp — que por defecto es true en las tres líneas de versión corregidas, de modo que la
actualización es suficiente por sí sola y no se necesita ningún cambio de configuración. El consumidor sigue
respondiendo 5.00 Internal Server Error, pero con una carga útil vacía, y ahora informa la excepción a
través del manejador de excepciones del consumidor, de modo que silenciarla no la oculta al operador.
También comprueba si el intercambio ha fallado, y responde a un fallo de ruta con 5.00 Internal Server Error
bajo la misma regla, donde antes respondía 2.05 Content.
Corregido en main en apache/camel#26994 (2245feac),
retroportado a camel-4.22.x en #27046 (868d5604) y a
camel-4.18.x en #27048 (aaf5bbf8).
Establezca camel.version en 4.22.2 y ejecútelo de nuevo. Verificado con 4.22.1 → 4.22.2:
1) ... response code: 5.00 (INTERNAL_SERVER_ERROR) response payload : <empty>
2) ... response code: 5.00 (INTERNAL_SERVER_ERROR) response payload : <empty>
3) ... response code: 5.00 (INTERNAL_SERVER_ERROR) response payload : <empty>
>>> NOT reproduced: the error payload was empty.
La sonda 3 también cambia el código, de 2.05 Content a 5.00 Internal Server Error — el fallo de la ruta ahora se
responde como un fallo.