このリポジトリは、CVE-2025-55182 の PoC 再現コードです。これは React Server Components (RSC) における深刻なセキュリティ脆弱性で、認証なしで任意のコード実行を可能にします。
この脆弱性は、React Server Components がクライアントリクエストから「Server Actions」をデシリアライズする方法に存在します。具体的には、requireModule 関数が、要求されたエクスポート名がモジュールの直接のプロパティであることを検証できていませんでした。これにより、攻撃者はエクスポートされた関数の constructor プロパティにアクセスし、グローバルな Function コンストラクタへの参照を取得でき、任意のコード実行に利用できました。
この PoC は、react-server-dom-webpack ライブラリの脆弱性を隔離するために最小限の Node.js 環境を使用します。これは、エクスプロイトがフレームワークの設定ミスではなく、ライブラリ自体のバグを実証していることを確認するためです。
npmnpm install
[!NOTE]
package.jsonは脆弱なバージョン19.0.0に固定されています。
このスクリプトは、脆弱な React ランタイムを使用してリクエストをデコードする生の HTTP サーバーをセットアップします。
# tty1
node --conditions react-server server.js
別のターミナルでエクスプロイトを実行します。これにより、悪意のある Flight ペイロードがサーバーに送信されます。
# tty2
node exploit.js id
応答にコマンドの出力が返されるはずです:
期待される出力:
Response: uid=0(root) gid=0(root) groups=0(root)
なぜこの脆弱性が発生したのか?
ReactFlightDOMServerNode.js の requireModule 関数は、クライアントが送信した name を基本的に何も検証せず信頼していました。そのプロパティが実際に公開される想定かどうかを確認せずに、moduleExports[metadata[NAME]] を実行していました。つまり、クライアントが「このプロパティが欲しい」と言えば、サーバーは「いいぜ、これだよ」と返していたようなものです。
なぜ任意のプロパティにアクセスさせることが問題なのか?
なぜなら、これにより誰でもプロトタイプチェーンに到達できてしまうからです。constructor にさえ到達できてしまうのは非常に危険です。モジュールが関数をエクスポートしている場合(例: module.exports = () => {})、その constructor は文字通りグローバルな Function コンストラクタです。
なぜ Function コンストラクタを取得すると RCE になるのか?
攻撃者は Function コンストラクタを取得すると、「Bound Server Action」機能を悪用できます。悪意のある JavaScript を含む文字列をそれにバインドします(実質的に new Function("evil code") に変換されます)。そしてそれが実行されると、サーバーは攻撃者が仕込んだ任意のコードを実行します。
なぜ React はその悪意のある関数を実際に実行するのか?
Server Actions は ID によってトリガーできるからです。攻撃者が module#constructor 参照を指す Action ID を含むペイロードを細工すると、React はそれを通常のアクションとして解決し実行します。その「アクション」は実際には悪意のある関数です。
なぜこれらは検証されなかったのか?
システムは、Server Reference メタデータの id と name が常に開発者が定義した有効なエクスポートを指すと想定していました。要求されたプロパティが実際のエクスポートであり、プロトタイプチェーンから継承されたものではないことを確認する hasOwnProperty のような安全チェックはありませんでした。
server.js なのか?生の server.js(とヘルパーの webpack-runtime.js)を使用して、React Server Components ランタイムを手動で設定しています。これにより次のことが可能になります:
module.exports = fn)にのみ機能します。実際のバンドラーは、設定によってエクスポートのラップ方法を変える可能性がありますけどね。react-server-dom-webpack 内部にあることを示せます。react-server-dom-webpack は Webpack バンドル内で実行されることを想定しています。私たちの webpack-runtime.js は、それが期待するグローバル(__webpack_require__、__webpack_chunk_load__)を提供します。
これは脆弱性をモックしているのではなく、ライブラリが実際に動作するために必要な最低限のランタイムを提供しているだけです。"Invalid PoCs" についての議論があります。これは、開発者が child_process.exec のような危険なものを意図的に公開している場合にのみ機能するものです。
この PoC はそのようなものではありません。通常の安全な設定で動作します。
公開される関数は無害です
アプリは単純な updateProfile 関数を公開します。これは単に文字列を返すだけで、シェルコマンドなどの怪しいものは一切ありません。
エクスプロイトはその関数を完全にエスケープします
この脆弱性により、攻撃者は安全なエクスポートを無視して、グローバルな Function コンストラクタである updateProfile.constructor に直接ジャンプできます。
核心的な問題はプロパティアクセスです
React は .constructor へのアクセスを許可すべきではありませんでした。開発者は Function コンストラクタを公開するつもりはありませんでした。代わりに、安全でないデシリアライズがそれをやってのけたのです。
唯一の実際の要件は、モジュールが関数を直接エクスポートしていること(module.exports = fn)です。これは CommonJS や多くのバンドラー設定で非常に一般的です。
exploit.js のペイロードは、3 つのチャンクで構成される React Flight メッセージを生成します:
id: "user-profile-action#constructor"。これは「コンストラクタをくれ」という意味です。bound: 引数を含むチャンク 2 を指します。["console.log('nice try, diddy!')"]: 悪意のあるコード文字列。React がこれをデシリアライズすると:
user-profile-action を解決します。.constructor プロパティを読み取ります => グローバルな Function を取得します。new Function("console.log('nice try, diddy!')")これが RCE です!
直ちにパッチ済みバージョンへアップグレードしてください:
react-server-dom-webpack >= 19.0.1react-server-dom-parcel >= 19.0.1react-server-dom-turbopack >= 19.0.1このパッチは、継承されたプロパティへのアクセスを防ぐ hasOwnProperty チェックを導入し、base64 ファイルアップロードを制限します。
パッチ済みバージョンに対してこの PoC を実行すると、サーバーは次のようにクラッシュまたはエラーになります:
$ node --conditions react-server server.js
Listening on http://localhost:3000
/path/to/CVE-2025-55182/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js:2726
resolvedValue = resolvedValue.bind.apply(
^
TypeError: Cannot read properties of undefined (reading 'bind')
at /path/to/CVE-2025-55182/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js:2726:43
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Node.js v20.19.3
これは、エクスプロイトが constructor プロパティへのアクセスに失敗したこと(Function ではなく undefined が返されたこと)、その結果後続の .bind 呼び出しが失敗したことを確認しています。
このコードは教育およびテスト目的のみです。所有していない、または明示的なテスト許可を得ていないシステムに対してこのエクスプロイトを使用しないでください。
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE の下で公開されています。