
この文書は、CVE-2025-55182 に関する私の個人的な研究プロセス、確認済みの調査結果、および私が実施した実験について説明するものです。これは、初期の誤った仮定と最終的な突破口を含む、私の調査の正直な記録です。
CVE-2025-55182(CVSS 10.0)に関する徹底的な調査の結果、私の当初の結論は、自動化された RCE は公に実証されておらず、悪用にはアプリケーション固有のガジェットが必要であるというものでした。この結論は誤りでした。
2025年12月5日、X(@maple3142)で別の独立した研究者から追加の洞察を得た後、私はアプリケーション固有のコードの脆弱性を一切必要とせずに、バニラの Next.js 上で完全な未認証 RCE を再現することに成功しました。
私の当初の焦点は、React 19.0.1 パッチにおける最初の変更点でした。
脆弱なバージョン(19.0.0):
return fn.bind.apply(fn, [null].concat(_ref));
パッチ適用後(19.0.1):
if (Array.isArray(promiseValue)) {
promiseValue = promiseValue.slice(0);
} else {
promiseValue = [];
}
私は、攻撃経路は配列の代わりに悪意のあるオブジェクトを使った fn.bind.apply() 経由であると想定しました。攻撃者が制御する bound を使った $ACTION_REF_ によって Server Actions に引数インジェクションが可能であることを実証できました。
curl -X POST http://localhost:9000/ \
-F '$ACTION_REF_0=' \
-F '$ACTION_0:0={"id":"<ACTION_ID>","bound":["; id #","/etc/passwd"]}'
結果: 引数は Server Action へのインジェクションに成功しました。ただし、これはターゲット関数がそれらの引数を安全でない方法で使用する場合にのみ RCE につながります。
パッチを詳しく調べると、getOutlinedModel() にもう一つの重要な変更があることがわかりました。
脆弱なバージョン:
for (key = 1; key < reference.length; key++)
parentObject = parentObject[reference[key]];
パッチ適用後:
if (hasOwnProperty.call(value, name)) {
value = value[name];
}
この脆弱な動作により、次のような参照を使ったプロトタイプチェーントラバーサルが可能になりました。
$1:__proto__:constructor:constructor
調査中に、.then プロパティを含む thenable オブジェクトをテストしました。
{"then": "$1:__proto__:constructor:constructor"}
JavaScript がこれを await で処理すると、以下のようになります。
.then プロパティを認識し、オブジェクトを Promise として扱うobj.then(resolve, reject) を呼び出すthen が Function.constructor に解決された場合、JavaScript は Function(resolve, reject) の実行を試みる観察された結果:
SyntaxError: Unexpected token 'function'
at Object.Function [as then] (<anonymous>)
Function.constructor が次のように呼び出された場合:
Function(resolve, reject)
// resolve.toString() = "function () { [native code] }"
// Function attempts to parse this as code → SyntaxError
resolve と reject の引数は常にネイティブの Promise 関数です。Function は最初の引数をソースコードとして解釈しようとしますが、これは無効な JavaScript です。
ここで私の研究は行き詰まりました。 Function.constructor への引数の制御は、アプリケーション固有のガジェットなしでは不可能だと結論付けました。
私の初期の調査結果を公開した後、別の独立した研究者が、私が見落としていた重要なピースを指摘しました。$B(Blob)デシリアライゼーションシンクです。
コンパイル済みの React Flight サーバーコード(TypeScript ソースにはない)には、次のコードが存在します。
case "B":
return response._formData.get(response._prefix + id);
場所:
[email protected]cjs/react-server-dom-webpack-server.node.unbundled.development.js[email protected]/dist/compiled/react-server-dom-webpack/このコードにより、React は 検証なしで、攻撃者が制御する入力から導出された値を使って response._formData.get() を呼び出すことができます。
| アプローチ | Function.constructor への引数 | 結果 |
|---|---|---|
| Thenable(フェーズ3) | resolve, reject(ネイティブ関数) | ❌ SyntaxError |
| Blob + 汚染されたレスポンス | _prefix(攻撃者が制御する文字列) | ✅ RCE |
以下を組み合わせることで:
$1:__proto__:then → Chunk.prototype.then)_response オブジェクト:
_formData.get が Function.constructor に設定されている_prefix が任意の JavaScript コードに設定されている$B 参照を含む内部モデルcase "B": ハンドラは以下を実行します。
Function.constructor("<attacker code>" + id)
これにより、引数バインディングの制限が完全に回避されます。
RCE を主張する一般的な GitHub PoC は、次のような Action ID を使用しています。
"child_process#execSync""vm#runInThisContext"これらは偽物です。 Next.js はアプリケーションが定義した Action ID のみを受け入れます。無効な ID は次のエラーを生成します。
TypeError: Cannot read properties of undefined (reading 'workers')
ただし、実際のエクスプロイトは偽の Action ID を必要としません。 有効な Server Action ID で動作します。
私はこのエクスプロイトチェーンを、以下の最小限の Next.js 15.0.3 + React 19.0.0 アプリケーションでテストしました。
async function myAction(data) {
"use server";
console.log("Server Action called with:", data);
return { success: true, received: data };
}
結果: 完全な RCE を確認しました。このアプリケーションには、安全でないコード、eval、execSync、ガジェットは一切含まれていません。
2025年12月5日時点で、$B シンクは Next.js 15.0.5(修正されたとされるバージョン)にまだ存在しています。
検証:
$ npm pack [email protected]
$ tar -xzf next-15.0.5.tgz
$ grep -A5 'case "B":' package/dist/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js
結果:
case "B":
return response._formData.get(response._prefix + obj);
コードは脆弱なバージョンと同一です。
この脆弱性が「修正済み」とされるバージョンで完全にパッチ適用されていない可能性があるという発見により、完全な実証コード(PoC)ペイロードは、Vercel と Meta のセキュリティチームによる検証が完了するまで開示を控えます。
この文書で提供される技術的詳細は、脆弱性のメカニズムを理解するのに十分ですが、即時の悪用を防ぐために意図的に不完全なものとなっています。
| 技術 | 状態 |
|---|---|
bound による引数インジェクション | ✅ 確認済み(影響は限定的) |
| プロトタイプトラバーサル | ✅ 確認済み |
thenable 経由の Function.constructor へのアクセス |
| 問題 | 影響 |
|---|---|
$B(Blob)デシリアライゼーションシンク | ❌ 重大 - 引数の制御を可能にする |
| コンパイル済みコードとソースコードの両方の調査 | ❌ シンクはコンパイル済み出力にのみ存在する |
| レスポンスオブジェクトの汚染メカニズム | ❌ すべての保護をバイパスできる |
CVE-2025-55182 は、バニラの Next.js アプリケーションに対する完全な未認証 RCE に悪用可能です。
$B デシリアライゼーションに関する洞察を得る$B デシリアライゼーションが依然として任意の _response オブジェクトを受け付けるかテストするNext-Action ヘッダー$@、__proto__、$B パターンを含む複雑なマルチパートペイロード$B デシリアライゼーションに関する突破口となる洞察は、X(@maple3142)の研究者によって提供されました最終更新日: 2025年12月5日
| 側面 | 調査結果 |
|---|
| 認証は必要か? | ❌ 不要 |
| アプリケーションガジェットは必要か? | ❌ 不要 |
| バニラの Next.js で動作するか? | ✅ はい |
| 必要なリクエスト数 | 1 POST |
| 影響を受けるバージョン | Next.js ≤15.0.4 + React 19.0.0 |
| CVSS スコア | 10.0(妥当) |
| ✅ 確認済み(ただし単独では悪用不可) |
| 脆弱なバージョンの検出 | ✅ 確認済み |