React2Shell:从 CVE-2025-55182 与 CVE-2025-66478 看 RSC 反序列化的系统性风险
2025 年 12 月披露的 CVE-2025-55182 (俗称 React2Shell)和 CVE-2025-66478,让 React Server Components(RSC)以及基于它的 Next.js App Router 走上了安全风口浪尖。两者本质上都是同一类问题的不同"落点":上游是 React 的 Flight 协议实现,下游是 Next.js 对该协议的集成,最终导致未认证远程代码执行(RCE)。
本文尝试从技术原理的角度,解释三个问题:
- 这次的"泄漏"具体是怎么发生的?
- 为什么会在 RSC 上出现这样的问题?
- 这种设计缺陷会不会在 Vue.js 或其他 SSR / RSC 方案中重演?
背景:RSC 与 Flight 协议在做什么?
React Server Components 的核心目标,是把一部分组件的渲染逻辑移到服务端执行,同时又保留 React 组件树的抽象。[web:4][web:24] 为了实现这一点,React 引入了一个内部协议(通常称为 Flight 协议),用来在客户端和服务端之间传输如下信息:
- 组件树结构和 props
- Server Components 的渲染结果
- Server Actions 的调用信息和返回结果
这套协议由一系列 react-server-dom-* 包来实现,负责把这些信息编码成一种自定义的流式格式,在服务端和客户端之间传输,并在另一端进行反序列化还原。[web:24][web:25]
从安全角度看,这里有一个很关键的事实:
协议数据直接驱动服务端"要加载哪个模块、调用什么东西",而不是简单的"数据展示"。 这为一类经典的"反序列化 → 执行"漏洞埋下了基础。
技术细节:RCE 链路是如何形成的?
在 CVE-2025-55182 / CVE-2025-66478 中,攻击面主要集中在服务端对 Flight payload 的解析过程。[web:3][web:21][web:24] 下面用抽象的方式描述漏洞链,不依赖具体代码行:
-
客户端可以构造 Flight payload
- 在实际应用中,任何可以触发 RSC 渲染或 Server Actions 的 HTTP 请求,最终都会携带某种形式的 Flight 数据到服务端。
- 这些数据包含了组件/模块引用、调用 ID、参数等高敏感信息。[web:24][web:30]
-
服务端对结构"信任过高"
react-server-dom-*在解析 Flight payload 时,会假设其中的结构大致符合预期:- 字段类型和层级是可信的
- 特定字段可以安全地用来映射到模块或导出
- 这些假设在正常场景是成立的,但在攻击场景下就变成了"隐含信任"。[web:3][web:21]
-
反序列化与对象展开缺乏安全边界
- 解析逻辑会把来自 payload 的字段合并到内部对象结构中,有的实现会对属性进行展开或按键名做特殊处理。
- 如果这里缺少对"危险键名"(例如可能影响原型链或内部状态)和"非法模块标识"的严格过滤,攻击者就可以通过精心构造的键值破坏内部对象结构,甚至实现原型污染。[web:25][web:33]
-
模块解析 / 执行与输入绑定过紧
- 某些字段会被用来决定要加载哪个 server 端模块、调用哪个导出或执行哪段逻辑。
- 当攻击者能控制这些字段时,就有机会让系统在"未预期的位置"加载并执行代码,形成 RCE。[web:3][web:24]
综合起来,这条链路可以概括为:
可控 Flight payload → 不安全反序列化(含属性展开/对象合并)→ 影响模块解析 / 调用路径 → 远程代码执行。
由于 RSC / Server Actions 在 Next.js App Router 中被广泛使用,且很多项目是按脚手架默认配置直接对外暴露,这条链路在现实生产环境中非常"短",因此被评为 CVSS 10.0,并已确认存在野外利用。[web:12][web:19][web:31]
为什么会发生:设计与实现上的双重问题
从工程视角看,这次事件既是实现细节上的漏洞,也是架构设计上的"安全债务"。
1. 协议设计:高权能数据通道
Flight 协议传输的不仅仅是数据,而是"如何在服务端执行/渲染"的指令集合。[web:24][web:34] 这意味着:
- 协议本身具有非常高的权能(capability)
- 任意一处对协议数据的信任,都可能演变成"执行层漏洞",而非简单的数据错误
在这种场景下,任何反序列化逻辑都应该默认把输入视为不可信攻击面,并强制施加白名单校验、严格模式解析和上下文隔离。
2. 实现细节:输入校验与边界防护不足
在公开分析中,多家安全团队指出了几个典型问题模式:[web:21][web:25][web:33]
- 对字段类型、枚举值、结构层级的校验不足
- 对"特殊键名"和可能影响内部对象结构的属性缺少专门过滤
- 模块解析逻辑直接依赖来自 payload 的标识,而这些标识的合法性没有被强约束
这些问题叠加,使得攻击者可以从"格式化数据"逐步演进到"控制调用路径",最终达成 RCE。换句话说,并不是单点 bug,而是一整条链条在安全侧缺乏系统性的约束。
3. Next.js 为什么中招?
Next.js 自 13+ 开始深度集成 RSC 和 Server Actions,App Router 更是默认 heavily 基于 RSC。[web:18][web:24] 在这样的设计下:
- Next.js 直接重用 React 的 Flight 协议及其实现,自然继承了所有相关的解析逻辑
- 为了提高开发体验,默认创建的项目就已开启 RSC / Server Actions,并暴露相关端点
因此 CVE-2025-66478 本质上是「上游 React 协议设计 + 实现问题」在 Next.js 应用层的具象表现:框架没有做额外的隔离或防护,而是把高权能协议裸露在了公网边界上。[web:12][web:18][web:24]
那 Vue.js 和其他 SSR / RSC 会不会有类似问题?
先给出结论:这两个 CVE 本身不会直接影响 Vue.js 或其他非 React RSC 框架,但"模式风险"是共通的。
1. 为何这两个 CVE 不影响 Vue?
- CVE-2025-55182/66478 绑定的是 React 19 系列的 RSC/Flight 协议及其在 Next.js 中的集成。
- Vue SSR 目前使用的是完全不同的渲染与数据传输机制,没有复用 React 的 Flight 协议,也没有使用
react-server-dom-*相关实现。[web:2][web:24][web:34]
因此,从实现上看,Vue.js 不会"继承"这两个具体漏洞;同理,SvelteKit、Nuxt 等其他框架如果没有引入相同的协议/逻辑,也不会直接在这两个 CVE 编号下中招。
2. 但风险模式是共通的
更值得关注的是这次事件暴露出的一个安全"模式":
一旦框架允许客户端"描述一段要在服务端执行的调用图",并在服务端通过反序列化来还原并执行,只要输入校验不严格,就很容易走向 RCE。
任何未来的服务器组件 / Server Actions / RPC 框架,如果具备以下特点,就需要特别小心:
- 自定义协议,复杂且高权能
- 协议携带"模块/方法标识 + 参数",驱动服务端执行
- 服务端解析时进行对象展开、属性合并或动态模块解析
在这种模型下,开发团队必须从一开始就把协议视为"安全边界界面",而不是"内部实现细节",并投入与「公开 REST API」同等甚至更高的安全设计和测试强度。[web:21][web:27][web:30]
对工程实践的启示
对已经使用 React / Next.js 的团队:
- 及时升级到官方发布的已修复版本,是当前唯一正确的选择。
- 对外暴露的 RSC / Server Actions 端点,建议在网关层增加额外的流量监控与访问限制,特别是降低不可信来源对这些端点的直接访问。
对在设计新一代 SSR / RSC / RPC 框架的团队:
- 把"自定义协议 + 反序列化"视为高危点,从设计阶段就引入安全审查。
- 优先选择"白名单 + 严格 schema 验证 + 上下文隔离"的方案,而不是宽松的动态解析。
- 对模块解析、动态加载等能力进行能力缩减与沙箱化,避免协议数据直接驱动任意模块/导出加载。
React2Shell 这次事件的价值,不仅在于修补一个严重漏洞,更在于提醒整个前后端一体化生态:当框架开始"帮你在服务端执行逻辑"时,它也需要承担相应级别的安全工程责任。
职场/工程圈常见的半开玩笑说法是:后端不要相信前端,前端不要相信用户输入 ,背后是一条严肃的安全原则:服务端永远不能信任来自客户端的一切内容,包括由"自己家前端"发来的。 唯一能信的是你自己在服务端重新校验过的东西。