CVE-2025-55182 · React2Shell:通过原型污染在 React Server Components 中实现 RCE
Source: Dev.to
TL;DR
React 的 Flight 反序列化器将任何具有 .then 方法的对象视为 Promise。通过使用精心构造的 multipart POST 污染 Object.prototype.then,攻击者可以迫使服务器通过 Function 构造函数执行任意 JavaScript。结果通过 X-Action-Redirect HTTP 头部泄露。无需身份验证。确定性。CVSS v3.1:10.0(关键)。
背景
React Server Components(RSC)在 React 19 中与 Server Actions 一起正式稳定。UI 组件在服务器上执行,并通过 Flight 序列化协议与客户端通信。当客户端调用 Server Action 时,会发送一个包含序列化负载的 multipart POST。服务器对负载进行反序列化,执行该动作,并将结果流式返回。
Flight 协议 不是 JSON;它是一种带有类型块的流式格式。其核心机制会将任何拥有 .then 函数的反序列化对象解析为 Promise。这个假设是漏洞的根源。
受影响范围: 使用 App Router 并启用 React Server Components 的任何 Next.js 应用(自 Next.js 14 起默认启用)。不需要显式定义 Server Actions;只要存在受漏洞影响的 RSC 包即可。
易受攻击的代码(React 19.0.0 – 19.2.0)
// VULNERABLE
if (obj && typeof obj.then === 'function') {
// behavioral check — bypassable via prototype chain
}
如果攻击者在 Object.prototype 上添加 then 函数,所有普通对象都会继承它。反序列化器无法再区分真正的 Promise 与被污染的对象,最终会执行:
new Function(_prefix) // attacker‑controlled code
利用步骤
侦察
识别运行 React 19.0.0–19.2.0 且使用 App Router 的 Next.js 应用。任何处理 multipart/form-data 并期望 Next-Action 头的端点都是有效目标。无需事先了解应用的路由。
负载构造
创建一个 multipart 请求体,使其:
- 将
__proto__:then设置为污染Object.prototype。 - 将
_formData.get重定向到$1:constructor:constructor。 - 在
_prefix中提供要执行的 JavaScript 代码。
请求发送
向根路径发送单个 POST 请求,携带头部 Next-Action: x。请求看起来是一个格式正确的 multipart 负载,因此大多数 WAF 会在不检查的情况下转发它。
服务端评估
在反序列化过程中,Flight 运行时遇到一个 .then 方法来源于已被污染的原型的对象,并调用 new Function(_prefix),从而执行攻击者的代码。
数据外泄
execSync() 的输出被插入到 NEXT_REDIRECT 错误摘要中。Next.js 将其转换为 307 响应,并在响应头中加入:
X-Action-Redirect: /login?a=
对 a 参数进行解码即可得到命令输出。
基本 RCE 示例
通过单个 POST 请求即可在受漏洞影响的 Node.js 服务器上执行诸如 whoami、id、uname -a 等命令。
完整利用资源
完整的负载结构、最小的 curl 单行命令以及利用框架 react2shell.py(包括持久交互式 shell、环境变量泄漏、网页篡改和选择性拒绝服务模块)已在 blog.deviannt.com 文档中记录。
补丁详情
代码更改
// VULNERABLE
- resolvedValue = resolvedValue[key];
// PATCHED
+ if (!resolvedValue.hasOwnProperty(key)) break;
+ resolvedValue = resolvedValue[key];
hasOwnProperty 检查阻止了原型链遍历,防止攻击者通过 $1:constructor:constructor 访问 Function 构造函数。
验证你的安装
node -e "const r = require('react'); const [maj,min,pat] = r.version.split('.').map(Number); \
console.log('React:', r.version, (maj===19 && (min<2||(min===2&&pat<1))) ? '❌ VULNERABLE' : '✓ Patched')"
补丁后建议
最初的补丁版本(19.0.1、19.1.2、19.2.1)仍包含两个后续 CVE:
- CVE‑2025‑55184 – 拒绝服务(CVSS 7.5)
- CVE‑2025‑55183 – 源代码泄露(CVSS 5.3)
请升级到 19.0.2、19.1.3 或 19.2.2 以获得完整修复。
结论
该漏洞源于依赖行为检查(typeof obj.then === 'function')而非身份检查。这种为支持“thenable”而设计的灵活性,在出现原型污染时就成了万能钥匙。必须进行恰当的原型链防护并采用更严格的类型验证,才能防止类似问题。
Full analysis → blog.deviannt.com · CVE‑2025‑55182 · React2Shell
— devianntsec, security research & beyond