你升的是 jackson-databind,中招的是 jackson-core:一个超长 JSON key 就能吃掉 200MB 堆

先说结论

如果你的项目里有 com.fasterxml.jackson.core:jackson-core(几乎一定有,jackson-databind 会把它带进来), 而版本落在下面任一区间,你中了一条 high,而 Dependabot 不会告诉你:

坐标 受影响 升到
com.fasterxml.jackson.core:jackson-core >= 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
tools.jackson.core:jackson-core(Jackson 3) >= 3.0.0, <= 3.1.5 3.1.6
同上 >= 3.2.0, <= 3.2.1 3.2.2

编号是 CVE-2026-68498(GHSA-649p-m576-vr99,high 7.5),FasterXML 2026-09-12 发在自己仓库的 Security 页上。 截至 2026-09-21 ,GitHub 全局漏洞库按这个编号查仍是 404 ------ Dependabot 和 OSV 读的就是那个库。

有一件事要先说清楚 :这不是「Jackson 又出了个 RCE」。它是内存耗尽型 DoS , 而且只有从字符输入解析时才中。下面每一节都会把边界写死。

为什么升了 databind 还会中

jackson-databindjackson-core两个独立发版的坐标 ,只是通常一起升。 jackson-core 在 Maven 生态里的被依赖数甚至比 databind 还高 ------ 很多项目会直接声明 它, 也有不少项目用 dependencyManagement 单独钉住过它的版本。

于是有一种很常见的状态:jackson-databind 已经是 2.21.6,jackson-core 还停在 2.21.5。 你的 SCA 面板全绿,因为它按 jackson-databind 查,而这条洞不挂在那个坐标上。

这和「同一个 Netty 版本号、不同模块的『修完』版本不一样」是同一类问题: 你脑子里的单位是「Jackson」,而 advisory 的单位是「坐标」。

洞本身:一道校验跑得太晚

StreamReadConstraints 里有两个独立的上限:

复制代码
maxStringLength  默认 100,000,000   ------ 管字符串「值」
maxNameLength    默认      50,000   ------ 管对象属性「名」

差了约 2000 倍maxNameLength 的存在意义就是:哪怕你允许很大的字符串值, 也别让一个属性名吃掉那么多内存。

字节输入路径做对了。UTF8StreamJsonParser 扫属性名时,每次扩缓冲都会调 ParserBase._growNameDecodeBuffer(),里面就有一次 validateNameLength() ------ 所以超长的名字在分配了几十 KB 之后就被拒掉了。

字符输入路径没有。ReaderBasedJsonParser._parseName2() 把名字累积进 TextBuffer, 而 TextBuffer.finishCurrentSegment() 调的是 validateStringLength() ------ 字符串上限,不是名字上限 。真正的 validateNameLength() 要等整个名字扫到闭引号、 进了 CharsToNameCanonicalizer.findSymbol() 才跑。

那时候内存已经分配完了。

官方公告里贴了实测输出,两条路径的差别一眼可见:

scss 复制代码
[bytes]  Name length (65536) exceeds the maximum allowed (50000, ...)
[reader] Name length (5000000) exceeds the maximum allowed (50000, ...)

字节路径在缓冲涨到 65,536 时就抛了;字符路径把整个 5,000,000 字符的名字读完了才抛 ------ 异常信息里那个数字本身就是证据。不设人为上限的话,这条路径能一直缓冲到 maxStringLength, 也就是约 1 亿字符(约 200MB),而且 maxDocumentLength 默认是关的 (-1),没有别的东西兜底。

一个请求几百 MB,几个并发就够把堆打爆。不需要任何误配置。

你到底中不中:一句话判据

  • String / Reader / char[] 解析不可信 JSON →
  • byte[] / InputStream 解析,或用非阻塞(async)解析器 → 不中

坏消息是,第一种恰好是最常见的写法之一 ------ HTTP 请求体先读成 StringobjectMapper.readValue(body, X.class),这行代码到处都是。

我自己的工具也漏了这一维

9 月 14 日我发过一个 jackson-check,扫 jar 判「你中哪几条、哪几条 Dependabot 看不见」。 它的判定表整张只有一个 artifactId:jackson-databind

所以它对 jackson-core 这 7 条公告是系统性失明的 ,而且不会报任何错 ------ 它只是安静地跳过所有 jackson-core-*.jar「没扫到」和「你很安全」在报告里长得一模一样。

这一版(v0.3.0)把判定粒度从「advisory × groupId × 区间」改成 「advisory × groupId × artifactId × 区间」,判定、求交集、「未扫到这个坐标」 全部以完整坐标为键。顺带把 jackson-core 那 7 条公告都收了进来。

⚠️ 上一版给 jackson-databind 的答案(2.18.10 / 2.21.6 / 2.22.2 / 3.1.6 / 3.2.2)没有错, 错的是维度 ------ 它只回答了一个坐标的问题。

工具

bash 复制代码
java -jar jackson-check.jar ./target ./src

零依赖单 jar,不联网,判定表内置。扫普通 jar、Spring Boot fat jar(BOOT-INF/lib/)、 传统 WAR(WEB-INF/lib/),坐标从 META-INF/maven/**/pom.properties 读,读不到才退回 MANIFEST 和文件名。

下面是 09-21 的真实输出 ------ databind 已经升到 2.21.6,core 还停在 2.21.5:

arduino 复制代码
【一】扫到的 jackson 构件(databind / core)
  com.fasterxml.jackson.core:jackson-core        2.21.5        (版本来源:pom.properties)
  com.fasterxml.jackson.core:jackson-databind    2.21.6        (版本来源:pom.properties)

【三】判定结果
  你的版本落在受影响区间内的:1 条
  其中 Dependabot 会报的:0 条(GitHub 全局漏洞库已收录)
  🔴 其中 Dependabot 看不见的:1 条(GitHub 全局漏洞库还没收录,按 GHSA 号查 404)

    CVE-2026-68498         high 7.5 Delayed maxNameLength enforcement for char-backed input ...
        坐标   com.fasterxml.jackson.core:jackson-core · 你的版本 2.21.5 · 受影响 2.19.0 <= 版本 <= 2.21.5
        条件   仅当从 String / Reader / char[] 解析不可信 JSON;从 byte[] / InputStream 解析不受影响
        未找到 CharInputParse
        说明   未在你的源码里找到触发条件(CharInputParse) ------ 🔴 这不等于安全

【四】该升到哪个版本(逐条求交集,不是照抄某一条 advisory)
  com.fasterxml.jackson.core:jackson-core
      现在 2.21.5  →  升到 2.21.6
      盖住 1 条;把目标顶到这么高的是 CVE-2026-68498

退出码:0 版本没中 · 2 版本中但源码里没找到触发条件 · 3 触发条件也成立 · 4 有文件读不动

最后那个 4 值得单说。ZipInputStream 遇到不是 zip 的文件不抛异常,只给零条目 ------ 扫描会正常走完、输出「没找到」、退出码 0。「我读不动它」于是变成了「你是安全的」。 所以这里单独占一个退出码。

🔴 工具做不到的那一半

它判得了 jar 版本,判不了你的调用方式。

readValue(body, X.class) 里的 bodyString 还是 byte[],文本扫描看不出来 ------ 那是个变量。工具只认得出显式写法(比如 new StringReader(...)), 所以报告里那句「未在你的源码里找到触发条件」后面永远跟着一句 「🔴 这不等于安全」

真要确认,只有两条路:看一眼你那几处反序列化入口的实参类型;或者直接升版本。 升版本更便宜。

这篇能证明什么、不能证明什么

:CVE-2026-68498 在 FasterXML 仓库公开可查;截至 09-21 全局库按编号查仍 404; 五个修复版在 Maven Central 上都拿得到;字节码实测 validateNameLength 的调用 只在修复版的 ReaderBasedJsonParser 里有、中招版里没有(2.18.9→2.18.10、 2.21.5→2.21.6、3.1.5→3.1.6 三条线都复现了)。

不能 :不能证明你一定会被打 ------ 得看你是不是从字符输入解析不可信 JSON; 不是说 Dependabot 对 jackson-core 全瞎 ------ 那 7 条里其余 6 条都已收录、正常告警,只有这一条没有; 也不是说 GitHub 永远不会收录它,AsyncHttpClient 那批就是晚了 39 天才收的。

工具、判定表生成脚本、发文前复核脚本都在仓库里(Apache-2.0): github.com/xiaoqiMikko... ------ 可直接下载的 jar 在 Release v0.3.0。

相关推荐
不正经的码狗1 小时前
Eclipse汉化(快速,推荐)
java·eclipse
极客互动API1 小时前
极客互动-企业微信基于外部API接口实现AI客服自动接管外部联系人消息收发
java·微信·企业微信·ai编程·rpa
Sam_Deep_Thinking1 小时前
关于java final关键字的可见性
java·后端·面试·程序员
tryxr1 小时前
矩阵的几种基础变换
java·数据结构·算法·矩阵
写后端的胖头鱼1 小时前
如何区分IO/CPU 密集型,线程池核心参数怎么设置
java·线程池·多线程·io密集·cpu密集
程序员若风1 小时前
CSRF攻击原理介绍和利用-腾讯云开发者社区
前端·网络·安全·web安全·网络安全·csrf攻击·腾讯云开发者社区
JAVA面经实录9171 小时前
IDEA 开发知识
java·intellij-idea·idea
于樱花森上飞舞2 小时前
【Redis】哨兵详解
java·开发语言·数据库·redis
2601_953824612 小时前
基于SSM的水果超市管理系统
java·tomcat·maven