ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

jackson-databind 升到 2.21.4 就安全了吗?不够,2.21.5 也不够了:现在要 2.21.7 / 2.18.11(2026-10-12 更正)

jackson-databind 升到 2.21.4 就安全了吗?不够,2.21.5 也不够了:现在要 2.21.7 / 2.18.11(2026-10-12 更正)

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.x2.18.82.18.92.18.11
2.21.x2.21.42.21.52.21.7
2.22.x—2.22.12.22.3
3.1.x3.1.43.1.53.1.7
3.2.x—3.2.13.2.3

差的就是最后那一位。而没有任何一条 advisory 会告诉你这件事—— 每条只管自己那一条,交集要你自己求。

把目标顶上去的是这三条:

  • CVE-2026-54515—— 大小写不敏感反序列化,绕过逐属性的@JsonIgnoreProperties
  • CVE-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 编号意味着什么:

  1. 你按 CVE 编号搜,搜不到它;
  2. 很多以 CVE 为主键的工具和台账里,压根没有这一行;
  3. 内部的漏洞跟踪单也大概率填不进去。

它是这 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.x

artifactId一模一样,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.4
  • tools.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 条里,绝大多数只在你用了某个特性的时候才成立:

触发条件关联条目
@JsonViewCVE-2026-54517 / 54518 / 59889 / GHSA-mhm7
@JsonTypeInfo/activateDefaultTyping/PolymorphicTypeValidatorCVE-2026-54512 / 54513
@JsonIgnoreProperties+ACCEPT_CASE_INSENSITIVE_PROPERTIESCVE-2026-54515
@JsonIgnore+@JsonProperty改名CVE-2026-54516
Java Record +PropertyNamingStrategy+@JsonIgnoreCVE-2026-59888
字段里有InetSocketAddressCVE-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,在文章里长得一模一样,区别只在有没有真的去数。

再说两条对这个工具不利的:

①「没找到触发条件」不等于安全。至少三种情况会让它变成假的安心:

  1. 你依赖的第三方库在它自己的代码里用了这些注解 —— 我们扫不到它的源码;
  2. 注解可能通过 mixin(ObjectMapper.addMixIn)等运行时方式加上,源码里根本没有那个词;
  3. 你可能压根没把源码目录传进来。

②「触发条件全部成立」也不等于确认中招。标记是按整个代码库聚合的,不是按同一个类或同一个字段。比如某条要求@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 已经不够。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进