2026-10-12 更正
本文写于 2026-08-07,当时官方一共 11 条公告,结论是升到 2.18.9 / 2.21.5 / 3.1.5。**这组版本号已经过时。**之后官方又发了几批公告,截至 2026-10-12,jackson-databind 与 jackson-core 合计 26 条,一次修完要升到2.18.11 / 2.21.7 / 2.22.3 / 3.1.7 / 3.2.3(五个版本在 Maven Central 上都拉得到)。
没变的:advisory 上写的修复版不是你该升的版本,交集得自己求;
GHSA-mhm7-754m-9p8w至今没有 CVE 编号;两个 groupId 的区间仍然贴串,那两个修复版在 Central 上仍然拉不到。变了的:第四节说「没有 Dependabot 盲区」只对当时那 11 条成立。现在 26 条里有 1 条(
CVE-2026-68498,jackson-core)GitHub 全局漏洞库没有收录,Dependabot 不会报它。正文其余数字(11 条、37 条规则、56 个测试)是 2026-08-07 的原貌;工具现在是 v0.4.0,判定表已跟到 26 条。
2026 年 jackson-databind 出了 11 条安全公告。如果你按 Dependabot 的提示、或者照着其中某一条 advisory 把版本升到了2.21.4,这篇文章是写给你的。
因为你还中三条,其中一条连 CVE 编号都没有。(这是 2026-08-07 的数;现在中的更多,见文首更正。)
先把结论摆出来,后面每一条都能自己复现。
结论:advisory 上写的修复版本,不是你该升的版本
这 11 条里,8 条都写着修复版是2.21.4/2.18.8/3.1.4。这个数字出现得太频繁了,频繁到你会以为它就是答案。
把 11 条逐条摆开求交集,真正的答案是这样:
| 维护分支 | advisory 上最常见 | 当时(11 条)盖得住全部的版本 | 现在该升到(2026-10-12,26 条) |
|---|---|---|---|
| 2.18.x | 2.18.8 | 2.18.9 | 2.18.11 |
| 2.21.x | 2.21.4 | 2.21.5 | 2.21.7 |
| 2.22.x | — | 2.22.1 | 2.22.3 |
| 3.1.x | 3.1.4 | 3.1.5 | 3.1.7 |
| 3.2.x | — | 3.2.1 | 3.2.3 |
差的就是最后那一位。而没有任何一条 advisory 会告诉你这件事—— 每条只管自己那一条,交集要你自己求。
把目标顶上去的是这三条:
CVE-2026-54515—— 大小写不敏感反序列化,绕过逐属性的@JsonIgnorePropertiesCVE-2026-59889——@JsonView对@JsonUnwrapped容器属性失效GHSA-mhm7-754m-9p8w——没有 CVE 编号
第三条值得单独说。
一、那条没有 CVE 编号的,是个补丁缺口
GHSA-mhm7-754m-9p8w讲的是@JsonView在@JsonTypeInfo(include = As.EXTERNAL_PROPERTY)的 creator 参数上失效。它的 advisory 原文里有这么一段:
This is a patch gap. GHSA-5hh8 (CVE-2026-54517) and GHSA-rcqc (CVE-2026-54518) descriptions cover only the main property-based path and the unwrapped-creator path respectively; the external-type-id creator path was fixed on the 3.x line via #6004 … butthe 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 vulnerableto the same
@JsonViewbypass technique via a different code path.
翻译过来就是:3.x 线修了,2.18 / 2.21 线的回移漏了。照着已发布的 advisory 升到 2.21.4 或 2.18.8 的人,仍然中招。这句话是官方自己写的,不是我推测的。
它后来在2.18.9/2.21.5里才被补上 —— 也就是上面那张表里多出来的那一位。
没有 CVE 编号意味着什么:
- 你按 CVE 编号搜,搜不到它;
- 很多以 CVE 为主键的工具和台账里,压根没有这一行;
- 内部的漏洞跟踪单也大概率填不进去。
它是这 11 条里最容易被整批漏掉的一条,偏偏又是那个「升到 2.21.4 还中」的直接原因。
二、Jackson 3 换了 groupId,而 advisory 把两个坐标的区间贴串了
这一条和上面那条无关,是另一个独立的坑,只要你在关注 Jackson 3 就会撞上。
Jackson 3 换了 Maven 坐标:
com.fasterxml.jackson.core:jackson-databind ← Jackson 2.x tools.jackson.core:jackson-databind ← Jackson 3.xartifactId一模一样,jar 文件名也一模一样(都叫jackson-databind-<版本>.jar),只有META-INF里才分得清。
去 Maven Central 拉maven-metadata.xml数一下,两个坐标各自发布过哪些大版本:
| 坐标 | 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.4tools.jackson.core上挂着1 条 2.x 的受影响区间,修复版写2.21.4
两边都去 Central 试着拉一下那个 jar:
https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/3.1.4/...jar → HTTP 404 https://repo1.maven.org/maven2/tools/jackson/core/jackson-databind/2.21.4/...jar → HTTP 404两个方向的修复版都不存在。为了排除「是不是我探测方式有问题」,同时跑了对照组:
tools.jackson.core 的 3.1.4 → HTTP 200 ✅ com.fasterxml.jackson.core 的 2.21.4 → HTTP 200 ✅同一套探测方法,对照组全通。所以不是探测坏了,是两个 groupId 的版本区间被交叉贴错了。
这件事的实际危害:照抄 advisory 的工具,会让你去装一个不存在的东西。你照着提示改 pom,构建时才发现拉不下来,然后开始怀疑自己的私服。
三、11 条不是都跟你有关
这是这篇文章里唯一一件 Dependabot 结构上做不到的事。
Dependabot 按版本匹配 —— 你装了受影响版本,它就把 11 条全报给你。但这 11 条里,绝大多数只在你用了某个特性的时候才成立:
| 触发条件 | 关联条目 |
|---|---|
@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 |
这些条件都在源码里,能扫。
我拿两份真实构件跑了对照。同一个jackson-databind-2.18.5.jar,只换源码:
| 你的代码 | Dependabot 报 | 触发条件真正成立 |
|---|---|---|
用了多态类型 +@JsonView的 web 层 | 7 条 | 6 条 |
只new ObjectMapper()做序列化 | 7 条 | 0 条 |
Jackson 3.1.2 那边是9 条 → 3 条。
差的那部分不是「不用管」,是排序:11 条一起丢过来,和「这 3 条你确实踩到了、先修这 3 条」,对排期的意义完全不同。
四、这个工具不能证明什么
写到这里得停一下,把边界说清楚。安全类的文章最容易在这里说过头,而说过头一查就穿帮。
先说一条对 Dependabot 有利的:这 11 条里没有 Dependabot 盲区。(2026-10-12 注:只对这 11 条成立;之后新发的公告里有 1 条CVE-2026-68498全局库没收,见文首更正。)
我把两个源摆在一起数过:官方仓库的 advisory 页面11 条,按两个坐标反查 Dependabot 实际用的索引,合计也是11 条,差值0。新坐标那边少的 2 条(CVE-2026-50193和GHSA-mhm7)对 3.x 本来就不适用,不是漏网。
所以这一批Dependabot 的版本告警是准的,别信任何说「Dependabot 全看不见」的文章。这个工具的价值在求交集和降噪,不在补漏。
顺带说下这个
0是怎么来的:它是量出来的,不是我默认的。我上一个工具做 Apache Shiro 时用同样的方法比过一次,那次比出来官方 26 条、按坐标反查只有 21 条,差 5 条。同样的方法这次得出 0 ——单源默认的「没有盲区」和量出来的 0,在文章里长得一模一样,区别只在有没有真的去数。
再说两条对这个工具不利的:
①「没找到触发条件」不等于安全。至少三种情况会让它变成假的安心:
- 你依赖的第三方库在它自己的代码里用了这些注解 —— 我们扫不到它的源码;
- 注解可能通过 mixin(
ObjectMapper.addMixIn)等运行时方式加上,源码里根本没有那个词; - 你可能压根没把源码目录传进来。
②「触发条件全部成立」也不等于确认中招。标记是按整个代码库聚合的,不是按同一个类或同一个字段。比如某条要求@JsonView和@JsonUnwrapped标在同一个属性上,而工具只能看到这两个词都在你的代码里出现过。
工具只做文本匹配,不做 AST 解析。这是故意的:关键路径得能被人读懂、自己核对 —— 一个看不懂的 AST 判定出错的时候,没有人能发现。
一句话:版本判定是硬的,触发条件判定只用来排优先级,不用来免除风险。
五、怎么用
零依赖单 jar,不联网,Java 17+。
# Maven 项目mvn package&&java-jarjackson-check.jar target src# 只有一个成品 jarjava-jarjackson-check.jar app.jar# Gradlejava-jarjackson-check.jar build/libs src/main/java路径可以是 jar / war / 目录。目录会同时找构建产物(定版本)和.java源码(定触发条件),两个都有才答得出「你真中几条」。
能认的形态:普通 jar、Spring Boot fat jar(BOOT-INF/lib/)、传统 WAR(WEB-INF/lib/),以及被 shade 进宿主 jar 的 jackson —— 那种情况依赖坐标层面看不见,但META-INF/maven还在,扫实物能看穿。
退出码0/2/3分别对应「版本没中」/「版本中但没找到触发条件」/「触发条件也成立」,可以直接塞进 CI。
仓库和 Release:https://github.com/xiaoqiMikko/jackson-check
六、判定表是生成的,不是手抄的
这类工具最怕的就是判定表抄错一位,而抄错的表看起来完全正常。
所以判定表由脚本从两个一手源生成:
- 官方仓库的 advisory 端点(维护者发布的条目全集 + 描述原文)
- GitHub 全局 advisory 库按坐标反查(Dependabot 实际用的那份索引)
11 条 advisory 展开成37 条「advisory × 坐标 × 版本区间」规则,带13 条断言,任何一条不满足就中止且不写文件—— 防的是「解析失败生成了一张空壳表,而测试照样全绿」。
几条关键的:
| 断言 | 查什么 |
|---|---|
| ASSERT2 | 两个源的条目数摆一起比,差值必须为 0 或被逐条解释 |
| ASSERT7 | 每个修复版逐个发 HEAD 请求探 Maven Central,拿不到的标出来 |
| ASSERT8 | 拉maven-metadata.xml,证明整条大版本线在那个坐标下真的不存在 |
| ASSERT9 | 逐分支求交集,且必须真的高于同分支最低修复版 |
| ASSERT11 | 每条触发条件的锚点词必须逐字出现在官方描述原文里 |
最后那条是防我自己的:不许凭印象给某条 CVE 标触发条件,官方原文里有那个词才算。
配套56 个单元测试,以及7 个真实构件端到端场景—— 用的是从 Central 下下来的真 jar(2.13.0 / 2.18.5 / 2.21.2 / 2.21.4 / 2.21.5 / 3.1.2 / 3.1.5),不是自己造的测试数据。
顺带一提,那 7 个真实场景又抓到 5 个 56 个单测全没测出来的问题,其中两个出在报告的归并和渲染层:同时装了两个 groupId 时,同一条 advisory 在两个坐标上都中,报告却只印一条;以及没扫源码时把结果印成了「触发条件部分成立」,而那句话是假的,根本没看过任何源码。两个都不报错,都得端到端跑一遍看报告才能发现。
发文之前还用OSV(api.osv.dev)这个完全独立的库,把上面所有承重数字重算了一遍 —— 不读生成脚本的任何输出。这篇文章里的每个数字都过了那一关。
如果你手上的项目还在 2.18 或 2.21 线,建议直接扫一遍。就算不用这个工具,也请把升级目标改成 2.21.7(2.18 线改成 2.18.11)—— 这是 2026-10-12 的数字,本文最初写的 2.21.5 / 2.18.9 已经不够。