三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

CVE-2026-29000 到底影响哪些包?我查错了一次(附离线排查工具)

CVE-2026-29000 到底影响哪些包?我查错了一次(附离线排查工具)

🔴 更正:这篇文章原来的核心结论是错的(2026-08-06)

本文最初的结论是「CVE-2026-29000 的官方 advisory 只列了 1 个包,实际有 5 个,
通过pac4j-oidc间接依赖的人 Dependabot 不会告警」。

这个说法不成立。官方 advisory 只列org.pac4j:pac4j-jwt,是对的。

我确实逐个解析了 Maven Central 上的 pom,也确实看到pac4j-oidc的 pom 里
写着pac4j-jwt这个坐标 ——但我没看scope

如果你因为这篇文章升级过 pac4j:那次升级不是必需的(升级本身无害)。
真正需要处置的,只有「你的应用里确实存在受影响版本的pac4j-jwt」这一种情况。

下面是重写后的正文。错在哪、怎么发现的,写在第三节,那部分可能比原文更值得看。

这个漏洞本身(这部分原文没错)

org.pac4j:pac4j-jwtJwtAuthenticator在处理加密 JWT(JWE)时,
某些路径下不强制校验签名。

攻击者只要拿到服务器的RSA 公钥—— 公钥本来就是公开的 ——
就能构造一个 JWE 包裹的 PlainJWT,把 subject 和 role 字段写成任意值,
以任意用户身份登录,包括管理员。不需要任何凭据。

CVSS10.0,满分。GitHub advisory 编号GHSA-pm7g-w2cf-q238,公开于 2026-03-05。

受影响范围就是官方 advisory 写的那三段,没有更多:

org.pac4j:pac4j-jwt < 4.5.9 -> 修复版 4.5.9 >= 5.0.0-RC1 且 < 5.7.9 -> 修复版 5.7.9 >= 6.0.4.1 且 < 6.3.3 -> 修复版 6.3.3

我原来的推理是怎么走偏的

pac4j 是个多模块项目。做 OIDC 单点登录的人引的是pac4j-oidc,
很少有人直接引pac4j-jwt。所以我去查:哪些兄弟模块会把pac4j-jwt带进来?

方法是从repo1.maven.orgorg.pac4j下全部 76 个 artifact 的maven-metadata.xml,
逐个版本下载 pom,看谁引用了pac4j-jwt。我找到了 4 个,于是得出「官方漏了 4 个包」。

这一步的数据是真的,结论是错的。因为 pom 里的每一条依赖还有一个scope,而我没看。

看了 scope 之后

pac4j-oidc -> pac4j-jwt scope=test javalin-pac4j -> pac4j-jwt scope=test lagom-pac4j-parent -> pac4j-jwt scope=provided ratpack-pac4j 1.4.6 -> 那段依赖整块被 XML 注释包着,根本不存在

pac4j-oidc我是逐版本核的:3.0.0、4.0.0、4.5.0、5.0.0、5.7.0、6.0.0、6.3.0,
全是test,无一例外

Maven 的规则是:testprovided依赖不会传递给下游使用者
它们只在这个模块自己编译和跑测试时存在。
所以你的项目引pac4j-oidc,Maven 不会把pac4j-jwt放进你的 runtime classpath。

光看 pom 我还不放心,又下载了真实构件复核了一次:

pac4j-oidc-6.0.0.jar 共 78 个条目,全部在 org/pac4j/oidc/ 下 没有任何 shade 进来的 pac4j-jwt 类

不传递依赖,也不打包携带 ——两条路都不通,使用者拿不到 pac4j-jwt

那个ratpack-pac4j 1.4.6尤其值得一提:grep 能搜到pac4j-jwt这个字符串,
因为它确实写在文件里 —— 但整段被<!--包着。XML 解析器看得见的东西,和 grep 看得见的不是一回事。

有一件事我想单独说:自校验为什么没拦住

原文里我专门写过一节叫「怎么确认我的数字没算错」,内容是:
把判定规则跑在 pac4j-jwt 全部 147 个版本上,命中114个,
而官方三段区间声明的版本数是 13 + 33 + 68 =114,精确吻合,
这条断言还写死在单元测试里,对不上就构建失败。

这个自校验本身没有任何问题,它今天依然是绿的。

问题是它验证的是「版本区间算法对不对」,而我的错误发生在「哪些构件该进这张表」——
它压根管不到那一层。

而当时我把它当成了整张表可信的证明。

校验通过的范围,不等于结论成立的范围。

更让我记住这一条的是:原文倒数第二节里,我还写着「判定规则错了不叫误报,是让人做错事」,
说的是上一个工具栽过的跟头。结果同一篇文章介绍的工具,犯了同一类错。

工具还在,已经修好

pac4j-check:单个 jar,零运行时依赖,Java 8 起可用,完全离线,不联网、不上传数据。

java -jar pac4j-check.jar ./myapp.jar # 扫一个 jar/war java -jar pac4j-check.jar /opt/apps # 扫一个目录(递归) java -jar pac4j-check.jar /opt/apps --json # JSON 输出

v0.2.0 删掉了那套「引入者」推断 —— 它的逻辑是「没看见 pac4j-jwt,但看见了 pac4j-oidc,
于是断定 jwt 也在」,在没有证据的情况下报警,而那个推断是错的。

原来断言这些误报的单元测试,现在反过来断言「不再误报」,免得哪天又改回去。

它现在只做一件事,但这件事mvn dependency:tree做不到:
直接扫构件本身,判断受影响版本的pac4j-jwt到底在不在。

  1. 递归展开 Spring Boot fat-JAR(在内存里,不解压落地)——
    生产机上往往只有一个打好的 jar,没有源码和 pom
  2. 识别被 shade 进宿主 jar 的情况—— 依赖树上根本不出现这个节点

退出码0/1/2,可以直接挂 CI。

你现在可以做的

  1. 确认你的应用里有没有受影响版本的org.pac4j:pac4j-jwt—— 直接依赖或传递依赖都算
  2. 如果在上面那三段区间里,升到对应的修复版本
  3. 只引pac4j-oidc而没有pac4j-jwt的,不受这个 CVE 影响—— 这正是我原来说反的地方

工具和完整数据都在:https://github.com/xiaoqiMikko/pac4j-check

原文我没有删除、也没有假装它不存在,错误的推理过程和更正都留在上面。
如果你发现我哪里还有错,欢迎开 Issue 指出来。

← 返回列表