ペンリジェント・ヘッダー

CVE-2025-66478 - Next.js サーバーアクションのサイレント RCE キラー

要旨

を開示した。 CVE-2025-66478 が2025年12月にリリースされることは、現代のウェブ・アプリケーション・セキュリティにとって重要な転換点となる。Next.jsのようなフレームワークが、クライアントとサーバーの境界を曖昧にし サーバーアクションこの脆弱性は、単純なインジェクションの欠陥ではない。この脆弱性は単純なインジェクションの欠陥ではなく、安全でないデシリアライゼーションに起因する高度なロジックのバグである。 プロトタイプ汚染にエスカレートする可能性がある。 リモートコード実行(RCE) 特定の条件下で。

この決定版ガイドは、基本的な勧告の域を超えている。JavaScriptのランタイムレベルで脆弱性を解剖し、リスクを生み出す正確なコードパターンを分析し、WAFのような境界防御が有効でない理由を説明し、AI主導のコンテキストを考慮した検証がいかに有効かを実証します。 寡黙この新しいパラダイムを確実なものにするために必要なことである。

新たなフロンティア:サーバー・アクションとシリアライゼーション・リスク

Next.jsサーバーアクション (サーバーを使用する)は、開発者がクライアントサイドのコンポーネントから直接サーバーサイドの関数を呼び出せるようにすることで、フルスタック開発に革命をもたらした。このシームレスなエクスペリエンスは、ネットワーク境界を越えてデータ(フォーム、オブジェクト、クロージャ)をマーシャライズする複雑なシリアライゼーション機構によって実現されています。

しかし、利便性はしばしばセキュリティを犠牲にします。CVE-2025-66478は、このハイドレイティングの過程でNext.jsが信頼されていない入力を処理する方法の根本的な欠陥を暴露しています。このフレームワークは、入力されたオブジェクトの構造を暗黙のうちに信頼し、攻撃者がJavaScriptオブジェクトの基本プロパティを操作できるようにしていました。

欠陥の解剖:試作品汚染からRCEまで

CVE-2025-66478は、その中核をなすものである。 プロトタイプ汚染 の脆弱性は、リクエストデータとServer Action引数のバインディング時に有効化されます。

メカニズム安全でない再帰的マージ

JavaScriptの動的な性質により、オブジェクトはそのプロトタイプからプロパティを継承することができる。ルート・プロトタイプは Object.prototype.攻撃者がこのルートプロトタイプを変更することができれば、実行中のアプリケーションインスタンス内のすべてのオブジェクトがその変更を継承します。

脆弱性は、サーバーアクションが複雑なデータ構造(ネストされたJSONや特別に細工されたJSONなど)を受け入れる場合に発生します。 フォームデータ)、フレームワーク、あるいはアクション内の開発者コードが、安全でない再帰的マージや代入を実行する。

攻撃ベクトル:

攻撃者は、以下のような特別なプロパティ・キーを使用してオブジェクト・プロトタイプ・チェーンをトラバースするように設計された、細工されたペイロードを送信します。 プロトコンストラクタ、またはプロトタイプ。

JSON

// サーバーに送信される攻撃ペイロードの概念 アクション { "userUpdate":userUpdate": { "__proto__":{isAdmin": true, "execPath":"/bin/sh" // RCEの可能性のあるガジェット }。}}

もしサーバー側のロジックが素朴にこの ユーザー更新 オブジェクトを既存のユーザーオブジェクトまたはコンフィギュレーションブロックに追加する場合、次のようになります。 __proto__ キーはデータ・フィールドとしてではなく、ターゲット・オブジェクトのプロトタイプを変更する命令として解釈される。

エスカレーションRCEガジェットチェーン

プロトタイプの汚染が最終目的であることは稀である。筋金入りのセキュリティ・エンジニアにとって、重要な問題は次のとおりだ: "公害を処刑に変えるには?"

これは「ガジェット」を見つけることを必要とします。「ガジェット」とは、危険な方法で事前定義されたプ ロパティを使用する、アプリケーションやその依存関係の中にある正当なコードの一部です。そのプロパティをグローバルに汚染することで、攻撃者はガジェットの振る舞いを制御します。

Node.js における RCE シナリオの例:

child_process.spawn()または同様のユーティリティを使用して子プロセスを生成するバックエンドプロセスを考えてみましょう。多くの場合、これらのユーティリティは options オブジェクトを受け取り、shell、env、execPath のようなプロパティを探します。

  1. 汚染:攻撃者は、CVE-2025-66478 をサーバーアクションで使用し、以下を汚染します。 Object.prototype.shell のような値で /bin/sh または コマンドエグゼ.
  2. トリガー:その後、アプリケーションのどこかで、まったく関係のない関数が spawn('ls', ['-la'], {}).
  3. 実行:なぜならオプション・オブジェクトは {} は汚染されたプロトタイプを継承する、 スポーン 見る { shell: '/bin/sh' }..コマンドはシェル内で実行され、引数を使ったコマンド・インジェクションが可能になる。

このエスカレーション・パスは、CVE-2025-66478 がクリティカルと評価されている理由を浮き彫りにしている。これは、データ処理エラーをサーバの完全な侵害に変えてしまう。

開発者のジレンマ:脆弱なコードパターンと安全なコードパターン

この脆弱性を特定するには、オブジェクト操作においてユーザー入力があまりにも暗黙的に信頼されている特定の「コード・スモッグ」を探す必要がある。

アンチパターン(脆弱なコード)

最もよくある間違いは フォームデータ または検証されていないJSONをオブジェクトに変換し、オブジェクト構造に依存するディープマージやデータベース操作を実行する関数に渡します。

ジャバスクリプト

`// app/actions/user.js 'use server'

import { db } from '@/lib/db'; // コードベースでよく見かける、一般的で安全でないディープマージユーティリティ import { deepMerge } from '@/utils/genericHelpers';

export async function updateProfileSettings(formData) { // DANGER: 信頼できない FormData を直接オブジェクトに変換する const rawInput = Object.fromEntries(formData);

// getCurrentConfig() は基本構成オブジェクトを返すと仮定します。
const currentConfig = await db.config.findFirst();

// 脆弱性のトリガー:
// deepMergeが明示的に__proto__をブロックしていない場合、
// 攻撃者はベース構成オブジェクトの型を汚染できます。
const newConfig = deepMerge({}, currentConfig, rawInput);

// 汚染されたコンフィグが保存されるか、危険な方法で使用される
await db.user.update({
    ここで{id: rawInput.userId }、
    data:{settings: newConfig }.
});

}`

セキュア・パターン(ゾッド・シールド)

大量割り当てとプロトタイプ汚染攻撃に対する唯一の強固な防御策は 厳格なスキーマベースの検証.のような図書館 ゾッド はアプリケーション・ロジックのファイアウォールとして機能し、許可されたプロパティのホワイトリストを作成し、それ以外のすべてを取り除きます。

ジャバスクリプト

`// app/actions/user.js 'use server'

import { z } from 'zod'; import { db } from '@/lib/db';

// DEFENSE: 厳密なスキーマを定義する。以下のキーのみが通る。// 任意の'プロトまたは不明なキーは自動的に取り除かれます。 const ProfileSettingsSchema = z.object({ userId:z.string().uuid(), theme: z.enum(['light', 'dark', 'system']), notificationsEnabled: z.boolean(), metadata: z.object({ bio: z.string().max(280).optional(), website: z.string().url().optional() }).strict() // .strict()はネストされたオブジェクト内の未知のキーを禁止します });

export async function updateProfileSettings(formData) { // STEP 1: 解析と検証 // safeParse は、成功した場合は型付けされたクリーンなオブジェクトを返し、エラーが発生した場合はエラーを返します。 const parseResult = ProfileSettingsSchema.safeParse( Object.fromEntries(formData) );

if (!parseResult.success) { // 不正な入力を内部構造を公開することなく、潔く処理する。
    // 内部構造を公開することなく、不正な入力を潔く処理する
    console.error('Validation failed:', parseResult.error);
    throw new Error('Invalid request data');
}

// STEP 2: サニタイズされたデータを使う
// parseResult.dataは、定義されたキーのみを含むことが保証されています。
await db.user.update({
    where:{id: parseResult.data.userId }、
    data:{
        theme: parseResult.data.theme、
        notifications: parseResult.data.notificationsEnabled、
        metadata: parseResult.data.metadata
    }
});

}`

CVE-2025-66478 ペンリジェント

従来のセキュリティ・レイヤーはなぜ失敗するのか

多くの組織は、既存の境界防御がCVE-2025-66478を捕捉してくれると信じている。この思い込みは危険だ。

WAF失明とフライトプロトコル

ウェブ・アプリケーション・ファイアウォール(WAF)は通常、URLパラメータやJSONボディのような標準的なHTTP要素に対する正規表現マッチングで動作し、SQLi(OR 1=1)またはXSS(<スクリプト)の署名。

しかし、Next.jsサーバーアクションの通信には フライト・プロトコル-テキストとバイナリデータの複雑なストリーミングハイブリッド。悪意のあるペイロードは、multipart/form-dataリクエストの中に深く入れ子になっていたり、あるいは、以下のような方法でシリアライズされている可能性がある。 __proto__ キーを単純な文字列マッチングから削除します。Next.jsのシリアライズ形式を特に理解していないWAFでは、無害なトラフィックが表示されます。

セマンティック・ギャップ

さらに {"constructor":{"prototype":"isAdmin": true}} {"プロトタイプ": {"isAdmin": true}} は構文的に有効なJSONである。WAFは、これが複雑なコンフィギュレーションオブジェクトを更新するために設計された 正当なリクエストなのか、攻撃なのかを判断できない。そのため 意味理解 ペリメーターに欠けているアプリケーション・ロジックの。

高度な検証:PenligentによるAI主導のアプローチ

手作業による監査や従来のツールの限界を考えると、新しいアプローチが必要である。 寡黙 は、アプリケーションのコンテキストを理解するように設計されたAI主導の侵入テストエンジンを利用している。

静的解析を超える:コンテキストを考慮したファジング

従来の静的アプリケーション・セキュリティ・テスト(SAST)ツールは、JavaScriptの動的な性質に苦戦し、多くの場合、偽陽性のフラグを立てたり、Server Actionの境界を横切る複雑なデータフローを見逃したりします。

PenligentのAIエンジンは、アプリケーションのAST(Abstract Syntax Tree)を解析して特定します:

  1. 情報源:マークの付いた機能 サーバーを使用する.
  2. シンク:オブジェクトのマージ、データベースの書き込み、コマンドの実行などの危険な操作。
  3. データフロー:信頼できない入力がソースからシンクに至る経路。

このコンテキストを理解することで、Penligentは、特定されたデータパスのプロトタイプ汚染をテストするために特別に設計されたターゲットファジングペイロードを生成します。

非破壊概念実証(セーフPoC)

本番環境をクラッシュさせることなく脆弱性の存在を証明することが最も重要です。Penligentは「安全なPoC」手法を採用しています。

Penligentエージェントは、RCEを試みたりアプリケーションの状態を破壊したりする代わりに、良性の一時的なプロパティを汚染しようとする。

  • アクション:エージェントはサーバーアクションにペイロードを送信します: {"__proto__":"penligent_validation_flag_{unique_id}": true}} {"__proto__": {"penligent_validation_flag_{unique_id}": true}}.
  • 検証:エージェントはその後、別のエンドポイントにリクエストを行い、応答データにグローバル汚染フラグが表示されているかどうかをチェックする。
  • 結果:このフラグが存在する場合、脆弱性は 100% の確度で確認され、ビジネスへの影響はゼロです。

Penligentの洞察:「最新のウェブ・アーキテクチャでは、セキュリティはネットワーク・レベルのブロックからアプリケーション・レベルのロジック検証へと移行しなければならない。AIはこのギャップを埋める唯一のスケーラブルな方法です。"

修復チェックリストの決定版

DevSecOpsチームやアーキテクトにとって、Next.js環境をセキュアにするためには早急な対応が必要だ。

  1. すぐにパッチを当てる:すべてのNext.jsインスタンスを次のようにアップグレードします。 v15.0.4+ または v14.2.16+.公式パッチには、シリアライゼーション中のある種のプロパティポイズニングに対するフレームワークレベルのハードニングが含まれている。
  2. スキーマ検証の実施:以下の方針を採用する。 すべて サーバー・アクションは、Zod、Yup、または Valibotを使った厳密な入力検証から始めなければならない。コードレビューでは、検証されていない入力を重大なセキュリティ違反として扱うこと。
  3. ディフェンシブ・コーディング:
    • ユーザー入力に対して一般的な「ディープマージ」関数を使用することは避けてください。
    • マージよりも、明示的なプロパティを持つ新しいオブジェクトを作成することを優先する: const newData = { prop1: input.prop1, prop2: input.prop2 };
    • の使用を検討する。 Object.create(null) ユーザー入力を保持するオブジェクトにプロトタイプがないことを確認する。
  4. ランタイム・ハードニング(核のオプション):最後の防衛策として、アプリケーション起動時にオブジェクトのプロトタイプをフリーズさせることができます。これは、プロトタイプの変更に依存するサードパーティ・ライブラリを壊す可能性があることに注意してください。 // instrumentation.jsまたはルートレイアウトで if (process.env.NODE_ENV === 'production') { Object.freeze(Object.prototype); Object.freeze(Array.prototype); }.

参考文献と権威リンク:

記事を共有する
関連記事