文章总结: 本文分析SpringforGraphQL分页游标反序列化RCE漏洞CVE-2026-59285,影响2.0.0至2.0.4版本,CVSS评分9.8。漏洞源于默认Cursor策略将定位对象序列化为JSON并base64编码,攻击者可通过可控after参数触发Jackson多态反序列化执行代码。建议立即升级至2.0.5,或收紧Jackson多态配置并验证ObjectMapper运行期配置。 综合评分: 88 文章分类: 漏洞分析,WEB安全,安全建设
Spring GraphQL反序列化RCE漏洞
云栖 云栖
云栖码客
2026年8月25日 01:16 安徽
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
Spring GraphQL反序列化RCE漏洞
8 月 20 号,Broadcom 一次发了 91 条 Spring 相关安全公告,光数量就够刷屏了。扫一圈标题,大部分是常规修补,但有一条值得你半夜爬起来看:Spring for GraphQL 的分页游标反序列化,编号 CVE-2026-59285。官方定级 HIGH,几家第三方跟踪平台给到的 CVSS 分冲到了 9.8。
先给结论,赶时间的人看到这行就可以去升级了:用 Spring for GraphQL 2.0.0 到 2.0.4 的项目,直接升到 2.0.5,没有中间值。
这个漏洞为什么和别的不一样
Spring for GraphQL 平时不太上安全头条,因为它本身不做数据绑定,真正的坑大多在 GraphQL Java 引擎或者你手写的 resolver 里。这次不一样,问题出在它自己的分页实现上。
GraphQL 生态里做分页,绕不开 Relay 的 Connection 规范。列表字段返回的不再是裸数组,而是一个带 pageInfo 和 edges 的 Connection 对象,每个 edge 上挂一个 cursor 字符串。翻页时客户端把这个 cursor 原样带回,服务端靠它定位到”上次读到哪了”。
问题就出在 cursor 上。它看起来是段乱码字符串,实际上 Spring for GraphQL 的默认策略是:把一个定位用的对象序列化成 JSON,再 base64 编码。反过来解码的时候,同样要拿 Jackson 把这个 JSON 还原成对象。
// 默认 CursorStrategy 干的事,本质是 JSON 对象 <-> base64 字符串
String raw = "{\"position\":42}";
String cursor = Base64.getUrlEncoder()
.encodeToString(raw.getBytes(StandardCharsets.UTF_8));
如果你的服务端定义了这样的分页字段:
@Controller
public class BookController {
@SchemaMapping(typeName = "Query", field = "books")
public Connection<Book> books(@Argument int first, @Argument String after) {
// 拿到 after 之后,Spring 会把 cursor 解码回定位对象
return bookService.findPage(first, after);
}
}
一旦 after 是攻击者可控的(分页参数天然就是),而 Jackson 又开了多态类型解析,攻击者就能在 cursor 里塞进一个 type id,让 Jackson 反序列化时去实例化 classpath 上的某个 gadget 类。gadget 链一旦跑通,就是远程执行代码。
这就是官方给的那四个触发条件:用 Spring for GraphQL、用 Jackson 2.x 做 JSON 反序列化、暴露了分页 Connection 字段、classpath 里碰巧躺着可被利用的 gadget 类。四条同时成立,才算真正暴露。
为什么 Jackson 一掺和就出事
老读者对这套打法应该不陌生。Jackson 的多态反序列化出过一长串 CVE,从 CVE-2020-24616 到今年几起,套路高度一致:攻击者控制类型标识,Jackson 顺着这个标识去加载类、实例化、填充属性。只要 classpath 里能拼出一条从”构造”到”执行”的链子,反序列化就成了任意代码执行。
Spring for GraphQL 这次的问题在于,cursor 这个入口太容易被忽略了。大家习惯性觉得 cursor 是服务端自己生成的、可信的,很少会去校验它的内容。可现实是客户端能把任意字符串塞进 after 参数,解码、反序列化一步不落全走了。
还有一层容易漏的:就算你没手动开 default typing,只要项目里某个地方配置过 Jackson 的多态行为,或者引了会自动开它的依赖,这个开关就是开着的。判断自己有没有踩坑,别只看有没有写 @JsonTypeInfo,得看运行期实际的 ObjectMapper 配置。
现在能做什么
第一件事永远是升级。2.0.5 是 OSS 修复版,2.0.4.1 只对买了商业支持的用户开放。
<dependency>
<groupId>org.springframework.graphql</groupId>
<artifactId>spring-graphql</artifactId>
<version>2.0.5</version>
</dependency>
如果暂时升不了,退而求其次的缓解手段是收紧 Jackson 的多态配置。把 activateDefaultTyping 关掉,或者用一个严格的白名单 PolymorphicTypeValidator,只放行你真正需要的类型,别让默认的宽松策略裸奔。
ObjectMapper mapper = JsonMapper.builder()
.polymorphicTypeValidator(BasicPolymorphicTypeValidator.builder()
.allowIfSubType("com.example.model")
.build())
.build();
再退一步,至少把 cursor 当成不可信输入看。它本应是 opaque 字符串,客户端不该有理由去解析它,你的服务端也不该对它做任何超出”解码回定位对象”以外的处理。
这条漏洞让我重新审视了一个假设:很多团队默认”服务端发出去的东西一定是干净的”。分页游标、JWT 里的 payload、回调里的签名前字段,全都被当成了可信输入。实际上只要它会绕一圈回到服务端、又经过反序列化,就该按不信任处理。这次是 GraphQL 的 cursor,下次可能就在别的协议里。
升级 2.0.5,顺带把 ObjectMapper 的多态配置过一遍,这两件事今天就能做完。
参考:spring.io/security/cve-2026-59285、Sonatype 对 8 月 20 日 Spring 公告批次的追踪分析。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:云栖码客 云栖 云栖《Spring GraphQL反序列化RCE漏洞》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论