如果你的项目用 pac4j 做单点登录,这篇值得花三分钟。
先说结论:CVE-2026-29000(CVSS 10.0)的官方 advisory 只列了一个包,
而实际上至少有 5 个包会把受影响的版本拖进来。
其中最常用的那个 —— pac4j-oidc —— 不在官方列表里。
这意味着:如果你是通过 pac4j-oidc 间接依赖的,Dependabot 不会给你告警。
这个漏洞有多严重
org.pac4j:pac4j-jwt 的 JwtAuthenticator 在处理加密 JWT(JWE) 时,
某些路径下不强制校验签名。
攻击者只要拿到服务器的 RSA 公钥 —— 公钥本来就是公开的 —— 就能构造一个 JWE 包裹的 PlainJWT,把 subject 和 role 字段写成任意值, 以任意用户身份登录,包括管理员。不需要任何凭据。
CVSS 10.0,满分。GitHub advisory 编号 GHSA-pm7g-w2cf-q238,公开于 2026-03-05。
pac4j 被 Spring Security、Apereo CAS、JEE、Vert.x、Play、Dropwizard 广泛集成, 它在 Maven Central 的下载量排在前 2%。
问题在哪:官方 advisory 只列了一个包
打开 GitHub 的 advisory,affected 数组里只有:
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-jwt 的。
pac4j 是个多模块项目。你要做 OIDC 单点登录,引的是 pac4j-oidc;
要接 CAS,引的是 pac4j-cas。pac4j-jwt 通常是被捎带进来的传递依赖。
我把 Maven Central 上的 pom 全解析了一遍
方法很笨但可复现:从 repo1.maven.org 拉 org.pac4j 下全部 76 个 artifact 的
maven-metadata.xml,逐个版本下载 pom,解析它引用的 pac4j-jwt 版本,再按官方区间判定。
结果:
| 构件 | 受影响版本数 | 官方 advisory 里有吗 |
|---|---|---|
org.pac4j:pac4j-jwt | 114 | ✅ 唯一列出的 |
org.pac4j:pac4j-oidc | 84 | ❌ 没有 |
org.pac4j:javalin-pac4j | 8 | ❌ 没有 |
org.pac4j:lagom-pac4j | 6 | ❌ 没有 |
org.pac4j:ratpack-pac4j | 1 | ❌ 没有 |
pac4j-oidc 那 84 个版本是重点。原因在它的 pom 里:
它和 pac4j-jwt 属于同一个 Maven reactor,声明依赖时不写版本号,
继承 pac4j-parent 的 ${project.version}。所以关系是恒等的 ——
pac4j-oidc:X 必然拖进 pac4j-jwt:X
也就是说,你用 pac4j-oidc 5.4.3,你就有 pac4j-jwt 5.4.3,而它在受影响区间里。 但你的依赖声明里只有 pac4j-oidc,而官方 advisory 不认识这个包。
另外三个(javalin / lagom / ratpack)是用 ${pac4j.version} 属性锁版本的,
对应关系不规则,只能逐版本查。顺带一提,ratpack-pac4j 从 2.0.0 起就不再依赖
pac4j-jwt 了,所以只有 1 个版本受影响 —— 这种细节不查 pom 是看不出来的。
怎么确认我的数字没算错
这是最该被质疑的地方,所以我先自己对了一次账。
把判定规则跑在 pac4j-jwt 在 Maven Central 上的全部 147 个版本上, 统计命中官方区间的数量,得到 114。
而官方 advisory 三段区间声明的版本数是 13 + 33 + 68 = 114。
精确吻合。 这条断言我写死在单元测试里了,对不上就构建失败。
基准对上了,上面那张表里「官方漏掉 4 个包」的增量结论才有意义 —— 否则连基准都算错,增量部分一文不值。
顺手写了个排查工具
既然要查,不如做成能直接跑的。单个 jar,25KB,零运行时依赖,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 输出
输出长这样:
[CRITICAL] pac4j-oidc 5.4.3
位置 :demo-app.jar!/BOOT-INF/lib/pac4j-oidc-5.4.3.jar
引入链 :pac4j-oidc:5.4.3 -> pac4j-jwt:5.4.3
⚠ 注意 :官方 advisory 未列出 pac4j-oidc,Dependabot 不会因此告警
处置 :升级 pac4j-jwt 至 5.7.9
它做三件 mvn dependency:tree 做不到的事:
- 递归展开 Spring Boot fat-JAR(在内存里,不解压落地)—— 生产机上往往只有一个打好的 jar,没有源码和 pom
- 识别被 shade 进宿主 jar 的情况 —— 依赖树上根本不出现这个节点
- 溯源引入链 —— 告诉你是哪个构件把它拖进来的
退出码 0 / 1 / 2,可以直接挂 CI。
两条我必须说清楚的局限
一、只覆盖了 org.pac4j 这一个 groupId。
有第三方研究称受影响构件共 19 个、1,020 个版本,但没公开完整清单。
我独立重建的是 org.pac4j 范围内的部分,不敢说已经覆盖全部。
其他 groupId(比如 Apereo CAS 的 org.apereo.cas)我没查。
二、pac4j-jwt 6.0.0 ~ 6.0.4 我标的是「存疑」,不是「受影响」。
官方说 6.x 从 6.0.4.1 起受影响;而第三方研究说这个缺陷早在 1.9.2 就引入了。
如果后者属实,这 5 个版本也该算进去。
但我没有独立验证过第三方那个结论,所以工具里把它们单独标出来提示人工确认, 而不是直接判成受影响。
保守的理由是:判定规则错了不叫「误报」,是让人做错事。 我在上一个工具上栽过一次 —— 版本上界写死,把已经修复的版本报成高危, 还建议人家去做代价高得多的大版本迁移。那不是误报,是错误的行动建议。
你现在可以做的
- 查一下你的项目有没有间接依赖 pac4j-jwt(尤其是通过 pac4j-oidc)
- 如果在受影响区间,按上面三段区间升到对应的修复版本
- 别把「Dependabot 没告警」当成安全 —— 这个 CVE 的官方数据就是不全的
工具和完整数据都在:github.com/xiaoqiMikko…
如果你发现我哪里算错了,或者有其他 groupId 的受影响构件,欢迎开 Issue 指出来。