
Offline checker for Thymeleaf CVE-2026-40477 / CVE-2026-41901 — tells you which of the two CVSS 9.0 SSTI flaws you are exposed to, and whether your version line has a fix at all (3.0.x: it does not)
Thymeleaf CVE-2026-40477 / CVE-2026-41901 离线排查工具 —— 零依赖、单 jar、不联网。
两条 CVSS 9.0 的 SSTI 绕过,九天内连出两个修复版。它先回答「我中了哪几条」, 然后回答那个更难受的问题:
我这条版本线,有没有能升的修复版?
对 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 一直到 全都列着。
而 Maven Central 上 3.0 线,之后再无发布:
1.0.03.0.15.RELEASEcurl -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 是官方明列的破坏性变更(逐条抄自官方 ChangeLog.txt 的 3.1.0.M1 段):
- 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.…} 的,升上去会直接报错,这些取值得改由 Controller 放进 Model。
这是一次要排期的迁移,不是改个版本号。
deps.dev 的依赖数(2026-09-04 直读,任何人可复算):
| 版本 | 依赖数 | 中哪几条 | 能同线升吗 |
|---|---|---|---|
| 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,比 3.1 线最高的 3.1.3 还高 36%,而它没有同线出路。
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 —— jar 被重打包工具改了名也认得出。
(Thymeleaf 官方 jar META-INF/ 下只有 MANIFEST.MF,没有 maven/ 目录,所以对它而言这是最硬的那条依据。)pom.propertiesfat jar / war 里的 BOOT-INF/lib/、WEB-INF/lib/ 会拆开逐个看,内嵌 jar 的 MANIFEST 也读。
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,所以照第一条 advisory 升到 3.1.4 的人,落在第二条里。
但别把它读成「官方没修干净」 —— 两条 advisory 描述的是不同机制,
3.1.4(2026-04-12)与 3.1.5(2026-04-21)两个官方版本相隔九天,
没有任何官方原文说前一个修复不完整。本工具只并排摆事实,不替你下这个结论。
RuleTable.java 里的每个数字都能回头核:
python tools/gen_rules.py --show
它拿两个一手源核对判定表 —— OSV 的受影响区间与逐版本清单、Maven Central 的
maven-metadata.xml —— 对不上就非零退出。
三条约定:
mvn package # JDK 17;target/thymeleaf-check-0.1.0.jar
mvn test # 19 个用例
运行时零依赖是刻意的:排查工具要能丢进任何环境直接跑。
Apache-2.0