
Офлайн-проверщик для Thymeleaf CVE-2026-40477 / CVE-2026-41901 — сообщает, какой из двух SSTI-дефектов с CVSS 9.0 затрагивает вас, и есть ли исправление для вашей версии вообще (3.0.x: его нет).
Инструмент офлайн-проверки Thymeleaf CVE-2026-40477 / CVE-2026-41901 — без зависимостей, один jar, без сети.
Два обхода SSTI с CVSS 9.0, два исправления за девять дней. Сначала он отвечает на вопрос «какие из них меня касаются», а затем на тот, что беспокоит сильнее:
В моей линейке версий есть исправленная версия, на которую можно обновиться?
Для 3.1.x — да (достаточно обновиться до 3.1.5.RELEASE).
Для 3.0.x и более ранних — нет — а именно это самая массовая установленная база.
Затронутый диапазон обеих advisory в OSV указан как introduced: 0:
curl -s https://api.osv.dev/v1/vulns/GHSA-r4v4-5mwr-2fwr | jq '.affected[0].ranges'
# [{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"3.1.4.RELEASE"}]}]
То есть вся линейка 3.0 попадает под уязвимость, в постатейном списке версий перечислены все от 3.0.15.RELEASE до 1.0.0.
А на Maven Central линейка 3.0 заканчивается на 3.0.15.RELEASE, после чего релизов больше не было:
curl -s https://repo1.maven.org/maven2/org/thymeleaf/thymeleaf/maven-metadata.xml \
| grep -o '<version>3\.0\.[^<]*</version>' | tail -1
# <version>3.0.15.RELEASE</version>
Исправления обеих CVE находятся в линейке 3.1. Поэтому у пользователей 3.0.x нет варианта «просто поменять номер версии» —
только миграция через мажорную версию — а 3.1 официально помечена как содержащая разрушающие изменения (дословно из раздела 3.1.0.M1 официального ChangeLog.txt):
- Removed web-API based expression security objects (#request, #response, #session, #servletContext).
- Removed support for Spring 3.x and Spring 4.x.
- Set minimum JDK compatibility level to JDK 8 project-wide (JDK 17 for thymeleaf-spring6).
Если в шаблонах использовались ${#request.…} / ${#session.…}, после обновления они сразу вызовут ошибку — эти значения придётся передавать через Model из Controller.
Это миграция, которую нужно планировать, а не смена номера версии.
Количество зависимостей по deps.dev (прямое чтение 2026-09-04, любой может пересчитать):
| Версия | Зависимостей | Какие CVE | Можно ли обновиться в той же линейке |
|---|---|---|---|
| 3.0.11.RELEASE | 1124 | обе | ❌ в линейке 3.0 нет исправления |
| 3.0.15.RELEASE | 678 | обе | ❌ то же, и это конечная версия линейки |
| 3.0.12.RELEASE | 641 | обе | ❌ |
| 3.1.3.RELEASE | 826 | обе | ✅ обновиться до 3.1.5 |
| 3.1.2.RELEASE | 677 | обе | ✅ |
| 3.1.4.RELEASE | 70 | только CVE-2026-41901 | ✅ |
| 3.1.5.RELEASE | 590 | — | уже безопасно |
Самый массовый отдельный релиз — 3.0.11.RELEASE, он на 36% выше, чем самый массовый в линейке 3.1 (3.1.3), и у него нет пути в рамках своей линейки.
java -jar thymeleaf-check.jar <путь к каталогу или jar/war> [--utf8|--gbk]
$ java -jar thymeleaf-check.jar ./target
[CRITICAL] ./target/myapp.war :: BOOT-INF/lib/thymeleaf-3.0.11.RELEASE.jar
Артефакт:thymeleaf версия 3.0.11.RELEASE (линейка 3.0, источник: MANIFEST(Implementation-Version))
Затронут: CVE-2026-40477 + CVE-2026-41901
Уязвим, и в линейке 3.0 на Maven Central нет никакого исправления (линейка заканчивается на 3.0.15.RELEASE).
Код выхода: 2 = есть артефакт, в чьей линейке версий нет исправления · 1 = уязвим, но можно обновиться в той же линейке / невозможно определить · 0 = не обнаружено · 3 = ошибка использования или пути.
Можно напрямую подключать в CI.
Сканируйте артефакты сборки (target/*.jar, *.war), а не исходники.
Thymeleaf в подавляющем большинстве случаев подтягивается транзитивно через spring-boot-starter-thymeleaf, а сам starter версию не задаёт —
в pom версии Thymeleaf вообще не видно. В таком случае инструмент прямо скажет «по pom определить невозможно», а не сделает вид, что его нет.
Три источника определения, по убыванию надёжности:
Implementation-Version из MANIFEST — распознаёт даже если jar переименован инструментами пересборки.
(В официальном jar Thymeleaf в META-INF/ только MANIFEST.MF, без каталога maven/, так что для него это самый надёжный источник.)pom.propertiesКаталоги BOOT-INF/lib/ и WEB-INF/lib/ внутри fat jar / war разбираются по отдельности, MANIFEST вложенных jar тоже читается.
CVE-2026-40477 | CVE-2026-41901 | |
|---|---|---|
| GHSA | GHSA-r4v4-5mwr-2fwr | GHSA-c9ph-gxww-7744 |
| CVSS | 9.0 | 9.0 |
| Затронуты | <= 3.1.3.RELEASE | <= 3.1.4.RELEASE |
| Исправление | 3.1.4.RELEASE | 3.1.5.RELEASE |
| Раскрытие | 2026-04-15 | 2026-05-04 |
| Официальная формулировка | "fails to properly restrict the scope of accessible objects" | "fails to properly neutralize specific constructs", происходит в sandboxed (restricted) контексте |
Затронутый диапазон второй включает 3.1.4, так что те, кто обновился до 3.1.4 по первой advisory, попадают под вторую.
Но не читайте это как «официально не дочинили» — в двух advisory описаны разные механизмы,
официальные версии 3.1.4 (2026-04-12) и 3.1.5 (2026-04-21) вышли с интервалом в девять дней,
и нигде в официальных текстах не сказано, что предыдущее исправление неполное. Этот инструмент лишь сопоставляет факты, а вывод за вас не делает.
Каждое число в RuleTable.java можно проверить задним числом:
python tools/gen_rules.py --show
Она сверяет таблицу判定 с двумя первоисточниками — диапазонами затронутых версий и постатейным списком версий из OSV, а также
maven-metadata.xml с Maven Central — при расхождении завершается с ненулевым кодом.
Три договорённости:
mvn package # JDK 17;target/thymeleaf-check-0.1.0.jar
mvn test # 19 тестов
Отсутствие зависимостей в рантайме — осознанное решение: инструмент проверки должен запускаться в любой среде без подготовки.
Apache-2.0