
Thymeleaf CVE-2026-40477 / CVE-2026-41901 オフライン調査ツール —— 依存ゼロ、単一 jar、ネットワーク不要。
CVSS 9.0 の SSTI バイパスが2件、9日間で修正版が2つ連続リリース。本ツールはまず「自分はどれに該当するか」に答え、 次にさらに厄介な問いに答えます:
このバージョン系列に、アップグレード可能な修正版はあるか?
3.1.x については、あります(3.1.5.RELEASE に上げれば完了)。
3.0.x 以前については、ありません —— そしてそこがまさに、導入台数が最も多い層なのです。
2件の 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 は公式が明記した破壊的変更です(公式 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 | 2項目 | ❌ 3.0 ラインに修正版なし |
| 3.0.15.RELEASE | 678 | 2項目 | ❌ 同上、かつこれは当該ラインの終点 |
| 3.0.12.RELEASE | 641 | 2項目 | ❌ |
| 3.1.3.RELEASE | 826 | 2項目 | ✅ 3.1.5 へアップグレード |
| 3.1.2.RELEASE | 677 | 2項目 | ✅ |
| 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"、サンドボックス化された(制限付き)コンテキスト内で発生 |
二つ目の影響範囲には 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
2つの一次情報源で判定表を照合する —— OSV の影響範囲とバージョン別リスト、Maven Central の
maven-metadata.xml —— 一致しなければ非ゼロで終了する。
3つの約束:
mvn package # JDK 17;target/thymeleaf-check-0.1.0.jar
mvn test # 19 个用例
実行時の依存関係ゼロは意図的なものです。調査ツールはどの環境にも放り込んでそのまま実行できる必要があります。
Apache-2.0
| コード | 意味 |
|---|---|
0 | スキャン完了、かつすべてのファイルを実際に読み込めた、対応が必要な検出結果なし |
4 | 読み込めないファイルがある —— zip でない、内容が切り詰められている、または読み取り失敗 |
🔴 4 は 2026-09-09 に追加されました。追加した理由は明確にしておく価値があります。
それ以前は、読み込めないファイルは出力に一行のヒントを残すだけで、終了コードは従来どおり 0 でした ——
痕跡は人間が見るものですが、CI やスクリプトが見るのは終了コードです。つまり「読み込めなかった」は自動化の中では「合格」と等しい意味になります。
破損した jar、暗号化された jar、ダウンロードが不完全な jar は、静かに「問題は見つかりませんでした」という一文に変わってしまいます。
「読み込めなかった」と「あなたは安全だ」は必ず別の言葉でなければなりません。
⚠️ 正当な空の jar は読み込めないうちには入りません(22 バイトの EOCD レコードは本物の空 zip です)、4 は発生しません ——
誤った警告が増えれば、本当の警告を誰も見なくなります。
その他の終了コードの意味については、上記の各判定段階と使用方法の説明を参照してください。