
Proof-of-Concept-Exploit für CVE-2026-22738, eine kritische SpEL-Injection-RCE in Spring AI SimpleVectorStore, die die Ausführung von OS-Befehlen ohne Authentifizierung demonstriert.
Nicht authentifizierte Remote-Codeausführung über Spring Expression Language (SpEL)-Injection in SimpleVectorStore.similaritySearch().
| Artefakt | Verwundbar | Behoben |
|---|
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 |
Fix-Commit: ba9220b22383e430d5f801ce8e4fa01cf9e75f29
SimpleVectorStore.similaritySearch() übergibt den vom Aufrufer gelieferten Filter-Schlüsselnamen unverändert in eine SpEL-Vorlage, die von StandardEvaluationContext ausgewertet wird. Da StandardEvaluationContext die vollständige JVM-Reflection-API offenlegt, kann ein Angreifer Folgendes injizieren:
T(java.lang.Runtime).getRuntime().exec(...)
in den Filter-Schlüssel, um eine nicht authentifizierte OS-Befehlsausführung zu erreichen.
Naive Injection funktioniert nicht ohne Weiteres — zwei Parser-Eigenheiten müssen umgangen werden:
' beginnt, wird als Zeichenfolge in Anführungszeichen behandelt; die äußeren Anführungszeichen werden entfernt, wodurch die Nutzlast verstümmelt wird."..." führt dazu, dass der Parser die äußeren doppelten Anführungszeichen entfernt und der innere SpEL-Ausdruck intakt als Schlüsselwert bleibt, der an #metadata['<KEY>'] übergeben wird.#metadata[''] auf beiden Seiten des injizierten Ausdrucks (anstelle einer undefinierten Variable) vermeidet einen unknown variable-SpEL-Fehler, während exec() dennoch ausgelöst wird.Der resultierende ausgewertete Ausdruck hat die folgende Form:
#metadata[''] + T(java.lang.Runtime).getRuntime().exec(new String[]{'/bin/bash','-c','<cmd>'}) + #metadata[''] == 'x'
Der HTTP-Antworttext enthält EL1030E — den SpEL-Laufzeitfehler:
operator ADD not supported between null and java.lang.ProcessImpl
Dieser Fehler wird nach der Rückkehr von exec() ausgelöst, was die OS-Befehlsausführung bestätigt, ohne dass ein Out-of-Band-Callback erforderlich ist.
Voraussetzungen:
pip install requests
Exploit ausführen:
python3 exploit.py [--target http://localhost:8082] [--wait]

Docker Desktop (macOS/Windows): für Callback-Nutzlasten host.docker.internal anstelle von 127.0.0.1 verwenden.
Der PoC führt fünf aufeinanderfolgende Schritte aus:
| Schritt | Beschreibung |
|---|---|
| 1 | Basisprüfung — bestätigen, dass der Endpunkt erreichbar ist und Seed-Daten zurückgibt |
| 2 | Blinder SpEL-Test — java.version über T(java.lang.System) auslesen, um den Injektionspunkt zu bestätigen |
| 3 | RCE: touch /tmp/pwned_cve_2026_22738 innerhalb des Containers |
| 4 | RCE: Ausgabe von id / uname / hostname in /tmp/rce_proof.txt schreiben |
| 5 | Verifizierung über docker exec — Inhalt der Proof-Datei ausgeben |
Dieser Proof-of-Concept dient ausschließlich Bildungs- und autorisierten Sicherheitstestzwecken. Verwenden Sie ihn nicht gegen Systeme, die Sie nicht besitzen oder für die Sie keine ausdrückliche schriftliche Genehmigung zum Testen haben.