
jackson-databind + jackson-core 26 条安全公告自查:按坐标逐条求交集给出真正到位的版本(2.18.11/2.21.7/2.22.3/3.1.7/3.2.3,2.21.6 已不够);扫源码降噪告诉你真中几条;含 1 条 GitHub 全局库未收录、Dependabot 不报的(jackson-core 那条,升了 databind 也照样中) CVE-2026-54515 / CVE-2026-54512
jackson-databind + jackson-core 共 26 条安全公告自查工具。零依赖单 jar,不联网。
它回答三个 Dependabot 回答不了的问题:
jackson-core 的 CVE-2026-68498 一条(见「v0.3.0」一节)。@JsonView / 多态类型 / 大小写不敏感匹配……),把「装了受影响版本」降噪成「真的踩到那个特性」。java -jar jackson-check.jar ./target ./src
09-30 和 10-01,FasterXML 又发了 4 条 high(都是 7.5,都是拒绝服务):
| 编号 | 坐标 | 主题 | 触发条件 |
|---|---|---|---|
| CVE-2026-91776 | jackson-databind | 每个未知 type id 都在进程生命周期的缓存里留一条,内存只增不减 | @JsonTypeInfo(use = Id.NAME, defaultImpl = …) + 攻击者能控制 type id + mapper 长期复用 |
| CVE-2026-91777 | jackson-databind | 前向引用按逆序补定义时比较次数约 N²/2(N=2000 → 2,003,000 次) | 把不可信 JSON 反序列化进带 @JsonIdentityInfo 的集合或 Map |
| CVE-2026-89425 | jackson-core | 畸形 token 被整个拼进异常信息,不受 maxErrorTokenLength 限制 | 只有 createParser(DataInput) 这条路径;公告写明没有配置能缓解 |
| CVE-2026-89407 | jackson-core | NumberInput.looksLikeValidNumber() 正则二次方回溯(16 万字符实测 74.4 秒) | 把 JSON 里的字符串绑定到数值字段(databind 默认行为);这条路径受 maxStringLength(默认 2000 万)而不是 maxNumberLength(默认 1000)约束 |
两个坐标的修复版同号:2.18.11 / 2.21.7 / 2.22.3 / 3.1.7 / 3.2.3(Central 全部可下载; 89407 在 3.2 线修在 3.2.2,89425 要 3.2.3,取大)。
所以 v0.2.0 / v0.3.0 印出来的 2.18.10 / 2.21.6 / 2.22.2 / 3.1.6 / 3.2.2 从 09-30 起不够了。 旧版本的 jar 不会知道这件事 —— 请换 v0.4.0 重扫。
⚠️ 这四条不是 Dependabot 盲区:它们发布当天就进了 GitHub 全局漏洞库,Dependabot 会正常告警。 v0.4.0 并入它们只是为了让「该升到哪个版本」这个答案保持正确。
🔴 同时更正 v0.2.0 的一个主张:下面「v0.2.0」一节写的「那 4 条 GitHub 全局漏洞库没收录、 Dependabot 不会报」截至 09-14 成立,2026-09-28 起已不成立 —— 四条都已被全局库收录 (
gen_rules.py的 ASSERT2 10-05 重跑:databind 侧盲区 4 → 0)。 现在唯一还查不到的是jackson-core的CVE-2026-68498。
jackson-core 是另一个坐标,扫 databind 扫不出它v0.2.x 的判定表整张只有 jackson-databind 一个 artifactId。于是 FasterXML 在
jackson-core 仓库发的 7 条公告,这个工具一条都扫不出来 ——
而它不会因此报任何错,只是安静地跳过所有 jackson-core-*.jar。
「没扫到」和「你很安全」在报告里长得一模一样。
v0.3.0 把判定粒度从 advisory × groupId × 区间 改成 advisory × groupId × artifactId × 区间,
判定、求交集、「未扫到这个坐标」全部以完整坐标为键。
最该注意的一条 —— CVE-2026-68498(high 7.5,2026-09-12):
StreamReadConstraints.maxNameLength(默认 5 万字符)在字符输入路径上没生效。
ReaderBasedJsonParser 累积属性名时调的是字符串长度上限(默认 1 亿,约 2000 倍),
真正的 name 校验要等整个 key 扫完才跑 —— 那时约 200MB 已经分配掉了。
单个超长 JSON key 即可,默认配置就中。
>= 2.16.0, <= 2.18.9 → 2.18.10 · >= 2.19.0, <= 2.21.5 → 2.21.6 ·
>= 2.22.0, <= 2.22.1 → 2.22.2 · 3.x(tools.jackson.core)<= 3.1.5 → 3.1.6 · <= 3.2.1 → 3.2.2UTF8StreamJsonParser 每次扩缓冲都重校验。
从 byte[] / InputStream 解析的不受影响;从 String / Reader / char[] 解析的才中。validateNameLength 的调用只在修复版的 ReaderBasedJsonParser 里有,
中招版里没有(2.18.9→2.18.10 · 2.21.5→2.21.6 · 3.1.5→3.1.6 三条线全复现)。⚠️ 工具能力边界,写在这里免得被误读:本工具判得了 jar 版本, 判不了你的调用方式 ——
readValue(someStringVariable, …)这种最常见的写法, 文本扫描看不出那个变量是String还是byte[]。 所以「未找到触发条件」不等于你不受影响,报告里也是这么印的。
🔴 不要读成「Dependabot 对 jackson-core 全瞎」:
jackson-core那 7 条里 只有CVE-2026-68498一条在 GitHub 全局漏洞库查不到,其余 6 条都已收录、Dependabot 正常告警。 这一条由gen_rules.py的ASSERT-C2每次重跑复核,数字一变就拒绝生成。
🔴 本节是 09-14 的记录,两处已过时(见上方「v0.4.0」):① 这 4 条已于 2026-09-28 被全局库收录, Dependabot 现在会报;② 「一次修完」的版本已不是 2.18.10 / 2.21.6 / 3.1.6。原文保留,不删。
FasterXML 在自己仓库的 Security 页上新发了 4 条:
| 编号 | 级别 | 主题 | 修复版 |
|---|---|---|---|
| CVE-2026-68497 | high 7.5 | 字符串绑定到 javax.xml.datatype.Duration / XMLGregorianCalendar 时数字长度无上限 → CPU DoS(默认 mapper 即可) | 2.18.10 / 2.21.6 / 2.22.2 / 3.1.6 / 3.2.2 |
| CVE-2026-19032 | medium 5.3 | java.nio.file.Path 反序列化不限制 URI scheme,可驱动任意已注册的 FileSystemProvider | 同上 |
| CVE-2026-83557 | medium 5.6 | 默认 PolymorphicTypeValidator 的拒绝列表漏了 Comparable | 同上 |
| CVE-2026-77310 | medium 5.3 | CVE-2026-54514 修得不完整:InetAddress 分支仍会立即做 DNS 解析 | 2.18.9 / 2.21.5 / 2.22.1 / 3.1.5 / 3.2.1 |
逐项实测:
jackson-databind:2.21.5 查询返回空。2.21.1(区间却是 >= 2.22.0, < 2.22.1),本工具按区间纠正为 2.22.1 并在生成时打印出来。# 照 v0.1 的建议已经升到 2.21.5 的项目
java -jar jackson-check.jar ./lib ./src
# 你的版本落在受影响区间内的:3 条
# 其中 Dependabot 会报的:0 条
# 🔴 其中 Dependabot 看不见的:3 条(GitHub 全局漏洞库还没收录,按 GHSA 号查 404)
# 现在 2.21.5 → 升到 2.21.6
新增两项触发条件扫描:
META-INF/services/java.nio.file.spi.FileSystemProvider,列出第三方 provider(实测能认出 jimfs);
源码里有 java.nio.file.Path 且依赖里有第三方 provider 才判「全部成立」。javax.xml.datatype.Duration / XMLGregorianCalendar,不认 java.time.Duration(那个满地都是,认了等于没降噪)。2026 年这 11 条里,8 条都写着修复版是 2.21.4 / 2.18.8 / 3.1.4。照着升的人以为修完了。
实际逐条求交集的答案是:
| 维护分支 | advisory 上最常见 | 真正到位的版本 |
|---|---|---|
| 2.18.x | 2.18.8 | 2.18.9 |
| 2.21.x | 2.21.4 | 2.21.5 |
| 2.22.x | — | 2.22.1 |
| 3.1.x | 3.1.4 | 3.1.5 |
| 3.2.x | — | 3.2.1 |
顶高目标的是这三条:
CVE-2026-54515 —— 大小写不敏感反序列化绕过逐属性 @JsonIgnoreProperties
CVE-2026-59889 —— @JsonView 对 @JsonUnwrapped 容器属性失效
🔴 GHSA-mhm7-754m-9p8w —— 没有 CVE 号,advisory 原文自己写着:
the fix was never backported to 2.21 or 2.18 … Users on 2.21.4 and 2.18.8 who upgraded per the published advisories remain vulnerable
它是一个补丁缺口:3.x 线修了,2.18 / 2.21 线的回移漏了。因为没有 CVE 号,按 CVE 编号是搜不到它的。
跑一次就能看到:
# 已经升到 2.21.4 的项目
java -jar jackson-check.jar ./lib ./src
# Dependabot 会报给你:3 条
# 🔥 注意:如果你照着 advisory 里出现最多的那个修复版升,以下 3 条仍然中
| 坐标 | Maven Central 上实际发布过 |
|---|---|
com.fasterxml.jackson.core:jackson-databind | 只有 2.x |
tools.jackson.core:jackson-databind | 只有 3.x |
而 advisory 的结构化字段里:
com.fasterxml.jackson.core 上挂着 6 条 3.x 区间,修复版 3.1.4 → 那个坐标下 HTTP 404tools.jackson.core 上挂着 1 条 2.x 区间,修复版 2.21.4 → 同样 HTTP 404照抄 advisory 的工具会让你去装一个不存在的东西。 本工具在生成判定表时逐个 HEAD 请求实测可获取性,拿不到的会在报告里标出来,不会印成升级建议。
两个坐标的 artifactId 和 jar 文件名一模一样,只有 META-INF 里分得清 —— 所以本工具按坐标判定,不按文件名。
| 触发条件 | 关联条目 |
|---|---|
@JsonView | CVE-2026-54517 / 54518 / 59889 / GHSA-mhm7 |
@JsonTypeInfo / activateDefaultTyping / PolymorphicTypeValidator | CVE-2026-54512 / 54513 |
@JsonIgnoreProperties + ACCEPT_CASE_INSENSITIVE_PROPERTIES | CVE-2026-54515 |
@JsonIgnore + @JsonProperty 改名 | CVE-2026-54516 |
Java Record + PropertyNamingStrategy + @JsonIgnore | CVE-2026-59888 |
InetSocketAddress 字段 | CVE-2026-54514 |
readTree() + JsonNode.toString() | CVE-2026-50193 |
同一个 2.18.5,两份代码的结果完全不同:
一份用了多态类型 + @JsonView 的代码 → Dependabot 报 7 条,真中 6 条
一份只 new 了个 ObjectMapper 的代码 → Dependabot 报 7 条,真中 0 条
两个方向都要说清楚,只说一边就是在误导:
①「未找到触发条件」不等于安全。 三种情况会让它变成假的安心:
ObjectMapper.addMixIn)等运行时方式加上,源码里根本没有那个词;②「触发条件全部成立」也不等于确认中招。 标记是按整个代码库聚合的,不是按同一个类或同一个字段。比如某条要求 @JsonView 和 @JsonUnwrapped 标在同一个属性上,而我们只能看到这两个词都在你的代码里出现过。
本工具只做文本匹配,不做 AST 解析。 这是有意的取舍:关键路径必须能被人读懂并自己核对 —— 一个看不懂的 AST 判定出错时没人能发现。
版本判定(第一步)是硬的;触发条件判定(第二步)只用来排优先级,不用来免除风险。
关于 Dependabot 盲区:本批 11 条一条都没有。 官方仓库 advisory 页面 11 条,按两个坐标反查合计 11 条,差值为 0 —— 这是查了两个源之后得出的结论,不是只查一个源的默认值(tools/gen_rules.py 的 ASSERT2 每次重跑都会重新核实)。所以这一批 Dependabot 的版本告警是准的,本工具的价值在降噪和求交集,不在补漏。