查出你实际装的 Tomcat 版本,并对每条 2026 年的 CVE 同时给出两套评级和触发条件。
零依赖单 jar,离线跑,不联网、不上传任何东西。
一、Spring Boot 项目的内嵌 Tomcat 版本,你的 pom 里没有。
它由 spring-boot-starter-parent 的 tomcat.version 属性管着,你在 pom 里只看得到
spring-boot-starter-web。所以本工具扫构建产物(jar / fat jar / 安装目录),不读 pom。
二、有些条目进不了 Dependabot 的告警。
2026 年 Tomcat 公布了 29 条 CVE,其中一部分因为两种机制不会出现在 Spring Boot 项目的告警里:
| 机制 | 说明 |
|---|---|
advisory 是 unreviewed | GitHub 只用 reviewed 的 advisory 做 Dependabot 告警。unreviewed 是 NVD 自动导入、尚未人工确认受影响包的正常流程状态 |
| 坐标对不上 | advisory 挂在 org.apache.tomcat:tomcat-coyote 等坐标下,而 Spring Boot 的依赖树里只有 tomcat-embed-core / -el / -websocket |
实际效果:一个内嵌 Tomcat 9.0.118 的 Spring Boot 应用,Dependabot 面板全绿, 本工具会报出 4 条命中,其中一条是默认配置即暴露。
三、两套评级体系口径不同,而你只看得到其中一套。
| ASF / Tomcat 官方 | GitHub / NVD | |
|---|---|---|
| 分级 | Low / Moderate / Important / Critical | CVSS 数值 |
| 依据 | 默认配置下的实际可利用性 | 向量机械计算,不看你开没开那个功能 |
| 在哪看 |
29 条里有 17 条两套评级差 2 级以上,最极端的 CVE-2026-41293:官方 Low,GitHub critical CVSS 9.8。
这不是谁报错了。 两套体系测量的本来就是不同的东西。 但要判断「该不该现在就升」,你需要同时看到它们 —— 以及你有没有开那个功能。
java -jar tomcat-check.jar <jar 或目录> ...
--all 连「不适用」的条目也列出来
--utf8 Windows 控制台中文乱码时加这个
# Spring Boot fat jar
java -jar tomcat-check.jar target/my-app.jar
# 独立安装的 Tomcat
java -jar tomcat-check.jar /opt/tomcat
# 整个依赖目录
java -jar tomcat-check.jar target/lib
需要 Java 17+。
每条命中给出:两套评级、触发条件、官方描述原文、以及这条会不会出现在你的 Dependabot 告警里。 最后给一个能覆盖全部命中条目的升级目标。
unreviewed 是正常流程状态。tools/gen_rules.py 从两个一手源生成 CveTable.java,一行都不手抄:
https://tomcat.apache.org/security-{9,10,11}.html —— 官方评级、标题、描述原文、影响区间type、受影响 Maven 坐标生成过程带 7 条断言,任一不满足就中止、不写文件。其中三条值得单说:
<strong>Moderate: The fix for <a>CVE-2025-66614</a> was incomplete</strong> <a>CVE-2026-32990</a>。
在整块里找「第一个 CVE」会取到标题里嵌的那个旧编号,后果不是少一条,是张冠李戴:
一条 CVE 挂上了另一条的标题和描述,而生成、测试、真实构件复验全部照常通过。Affects: 行紧挨着下一条 CVE 的标题,
极容易配对到错误的那一条 —— 错了会得到一张「看起来完全正常但整体错位一格」的表。
用 GitHub 的 first_patched_version 交叉校验,开发时真的靠它抓到过一次错位。tomcat-embed-* 里。
排除依据必须是实测,不能是「我记得」。重新生成:
python tools/gen_rules.py
mvn clean package # → target/tomcat-check.jar
34 个测试。运行时零依赖,JUnit 仅测试期。
MIT
tomcat.apache.org/security-9.html |
| Dependabot 直接推送给你 |