CVE-2026-63030

CVE-2026-63030 Vulnerability Report — WordPress REST API Batch Route Confusion (WP2Shell RCE)

概要

項目 内容
CVE番号 CVE-2026-63030
公開日 2026-07-17
最終更新 2026-07-18
CVSS v3.1 9.8 (Critical) — WPScan採点
CVSS Vector (WPScan) AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CVSS Vector (CISA-ADP) 7.5 (High) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
CWE CWE-436 (Interpretation Conflict)
EPSS 【情報不足】NVD未算出時点
CISA KEV 【要確認】2026-07-18時点では未登録
GHSA GHSA-ff9f-jf42-662q (Critical)
関連CVE CVE-2026-60137 (GHSA-fpp7-x2x2-2mjf) — WP_Query SQLインジェクション
発見者 Adam Kues at Assetnote / Searchlight Cyber
ニックネーム "WP2Shell"

【重要】CVSSスコアの差異について:

これは連鎖攻撃の総合評価と単体脆弱性の評価の違いである。

影響を受けるソフトウェアおよびバージョン

バージョンブランチ 影響範囲 修正バージョン 影響を受ける脆弱性
WordPress 6.9.x 6.9.0 – 6.9.4 6.9.5 CVE-2026-63030 + CVE-2026-60137 (連鎖RCE)
WordPress 7.0.x 7.0.0 – 7.0.1 7.0.2 CVE-2026-63030 + CVE-2026-60137 (連鎖RCE)
WordPress 7.1 beta 7.1 beta1 7.1 beta2 CVE-2026-63030 + CVE-2026-60137 (連鎖RCE)
WordPress < 6.9 影響なし(バッチルート混同は6.9で導入)

技術詳細

脆弱性の概要

CVE-2026-63030は、WordPress 6.9で導入されたREST APIバッチエンドポイント(/wp-json/batch/v1)における「ルート混同(route confusion)」の脆弱性である。

バッチ処理の検証ループにおいて、不正なpathを含むサブスクリプトがWP_Errorとして処理される際、$matches配列への追加が省略された。これにより、$matches配列と$validation配列のインデックスがズレ、あるサブスクリプトのリクエストが別のサブスクリプトのルートハンドラで実行される状態が発生する。

単独では「認証バイパス」ではなく「ルート混同」だが、CVE-2026-60137(author__not_inのSQLi)と連鎖することで、認証なしのRemote Code Executionに至る

根本原因

脆弱なコードは wp-includes/rest-api/class-wp-rest-server.phpserve_batch_request_v1() メソッド内に存在した。

❌ 脆弱な実装 (コミット fa72c12 以前のコード)

バッチ検証ループの制御フロー:

// バッチ検証ループ
foreach ( $requests as $i => $single_request ) {
    if ( is_wp_error( $single_request ) ) {
        $has_error = true;
        // ⚠️ $validation にのみ追加 — $matches には追加されない!
        $validation[] = $single_request;
        continue;
    }
    // ... ルートマッチング処理 ...
    $matches[] = $handler;
    $validation[] = $validation_result;
}

インデックスズレの発生メカニズム:

requests:    [error,   request A,  request B]
validation:  [error,   result A,   result B]
matches:     [match A, match B]
              ↑ index 0が欠落 → indexが1つズレる

実行ループでは $matches[$i]$validation[$i] を参照するため:

✅ 修正後の実装 (コミット fa72c12879fbfda17d450fc1fd919f698f549f4d)

if ( is_wp_error( $single_request ) ) {
    $has_error = true;
    // ✅ $matches にもダミーエントリーを追加してインデックスを維持
    $matches[] = $single_request;
    $validation[] = $single_request;
    continue;
}

追加の防御層:

rest_api_loaded()WP_REST_Server::serve_request() にも is_dispatching() チェックが追加され、バッチ処理中に新たなRESTサイクルが開始されることを防ぐ。

// rest_api_loaded()
if ( isset( $GLOBALS['wp_rest_server'] )
    && $GLOBALS['wp_rest_server'] instanceof WP_REST_Server
    && $GLOBALS['wp_rest_server']->is_dispatching()
) {
    return;
}

// WP_REST_Server::serve_request()
if ( $this->is_dispatching() ) {
    return false;
}

修正コミット詳細

項目 内容
修正コミット fa72c12879fbfda17d450fc1fd919f698f549f4d
コミットメッセージ "REST API: sub-requests must always use dispatch."
変更ファイル数 2ファイル
変更ファイル wp-includes/rest-api.php, wp-includes/rest-api/class-wp-rest-server.php
行数変更 +27 行追加
新規関数 WP_REST_Server::is_dispatching()

RCE連鎖の仕組み

47Cid/wp2shell-lab の分析に基づく完全な連鎖フロー:

[攻撃者] → POST /wp-json/batch/v1
    ↓
 serve_batch_request_v1() — Loop 1 (validate)
    ↓
 [0] "http://:" → wp_parse_url fails → WP_Error (matchesに追加されない)
 [1] POST /wp/v2/posts → match: posts_handler
 [2] POST /batch/v1 → match: batch_handler
    ↓
 $validation: [error, OK(posts), OK(batch)]
 $matches:    [posts_handler, batch_handler]  ← index 0欠落
    ↓
 serve_batch_request_v1() — Loop 2 (dispatch)
    ↓
 i=0: error → skip
 i=1: POST /posts → $matches[1] = batch_handler
    → postsリクエストのbodyがネストされたバッチとして処理される
    ↓
 ネストバッチ内のLoop 1 (validate):
 [0] "http://:" → WP_Error
 [1] POST /wp/v2/categories → match: categories_handler
 [2] GET /wp/v2/posts → match: posts_handler
    ↓
 ネストバッチ内のLoop 2 (dispatch):
 i=1: POST /categories → $matches[1] = posts_handler
    → categoriesリクエストがpostsのget_items()で処理される
    → author_exclude が categories スキーマにない → サニタイズされない
    → postsが author_exclude → WP_Query::author__not_in にマッピング
    ↓
 WP_Query::author__not_in — CVE-2026-60137 (SQLi)
    ↓ スカラー値が直接SQLに埋め込まれる
 [MySQL] → SQLインジェクション実行
    ↓
 管理者パスワードハッシュ窃取 → クラック → 管理者ログイン
    ↓
 プラグインアップロード → RCE

重要な技術的ポイント:

  1. バッチエンドポイントはWordPress 5.6(2020年11月)から存在するが、ルート混同は6.9(2025年12月)で導入
  2. Cloudflareの分析によれば、永続オブジェクトキャッシュが無効な環境でRCEパスに到達可能(デフォルト設定)
  3. respond_to_request() は依然として permission_callback を呼び出すため、この脆弱性は「認証バイパス」ではなく「ルート混同」— 公開読み取り可能なエンドポイント(postsのviewコンテキスト)を経由してSQLiに到達する

攻撃フロー

[攻撃者] → POST /wp-json/batch/v1
    ↓
[REST API Batch Endpoint] — CVE-2026-63030 (ルート混同)
    ↓ インデックスズレによりpostsリクエストがbatch_handlerで処理
[ネストバッチ処理] → categoriesリクエストがposts_handlerで処理
    ↓ author_excludeパラメータがサニタイズされずWP_Queryに到達
[WP_Query::author__not_in] — CVE-2026-60137 (SQLi)
    ↓ スカラー値が直接SQLクエリに埋め込まれる
[MySQL] → 管理者パスワードハッシュ返却
    ↓ ハッシュクラック
[管理者ログイン] → プラグインアップロードでPHP配置
    ↓
[RCE] — 任意のOSコマンド実行

トリガー条件

条件 詳細
バージョン 6.9.0 – 7.0.1
認証 不要 (匿名で到達可能)
プラグイン 不要 (Coreのみで成立)
永続オブジェクトキャッシュ 無効な環境で exploitation が容易(Cloudflare分析)
REST API 有効である必要あり(デフォルトで有効)

PoC/Exploitの状況

項目 状況
公開PoC あり — SQLi検証PoCが複数公開済み、完全RCEチェーンは未公開
教育用ラボ あり — 47Cid/wp2shell-lab (root cause analysis + Docker lab)
PoCリポジトリ Icex0/wp2shell-poc, Senanfurkan/wordpress-cve-2026-63030, attackercan/wp2shell-poc2
Exploit成熟度 PoC (SQLi確認済み) → 完全RCEチェーンは未公開
実利用 PatchStackが2026-07-17に攻撃を観測報告(詳細不明)
Searchlight Checker wp2shell.com — 脆弱性チェック用公開ツール

⚠️ 注意: SQLiコンポーネントのPoCは公開・検証済み。完全RCE(ハッシュクラック→ログイン→プラグインアップロード)の完全なエクスプロイトコードはSearchlightによって公開されていないが、OpenSourceの性質上、パッチリバースエンジニアリングによる再現は時間の問題と予測される。

実被害・インシデント

検出方法

ブラックボックステスト

バッチエンドポイント到達性確認

# テストA: 標準RESTパス
curl -sX POST "https://target.com/wp-json/batch/v1" \
  -H "Content-Type: application/json" \
  -d '{"requests":[]}'
# 期待応答: {"code":"rest_missing_callback_param","message":...}

# テストB: クエリパラメータパス
curl -sX POST "https://target.com/?rest_route=/batch/v1" \
  -H "Content-Type: application/json" \
  -d '{"requests":[]}'

バージョン確認

curl -sL "https://target.com/" | grep -oP 'content="WordPress [^"]*"'
# 6.9.0 – 6.9.4 または 7.0.0 – 7.0.1 → 影響あり

WAFルール (Cloudflare)

ルール説明 Managed Ruleset ID Free Ruleset ID デフォルトアクション
WordPress - Unauthenticated RCE 7dfb2bd4708d4b88b9911dc0550664b6 ebd3f2df15c74ddcbf6220c9b5ec246a Block

ホワイトボックステスト

修正確認

# is_dispatching() チェックの存在確認
grep -n "is_dispatching" wp-includes/rest-api.php
grep -n "is_dispatching" wp-includes/rest-api/class-wp-rest-server.php

# $matches[] = $single_request の存在確認(serve_batch_request_v1内)
grep -n 'matches\[\].*single_request' wp-includes/rest-api/class-wp-rest-server.php

対策

恒久的対策

現在のバージョン 推奨アクション 修正バージョン
6.9.x 6.9.5に更新 6.9.5
7.0.x 7.0.2に更新 7.0.2
7.1 beta1 7.1 beta2に更新 7.1 beta2

暫定対策・軽減策

  1. REST APIバッチエンドポイントのブロック:

    • WAFで /wp-json/batch/v1?rest_route=/batch/v1 へのアクセスをブロック
    • プラグイン「Disable WP REST API」で匿名アクセスを制限
    • mu-プラグインでREST batchルートの認証を必須化
  2. Cloudflare WAF:

    • 2026-07-17 17:03 UTCに新ルールが全プランに自動デプロイ済み
    • Managed Rules / Free Ruleset の両方で新ルールが有効か確認
  3. Wordfence:

    • Wordfence Premium/Care/Response: 2026-07-17にファイアウォールルール配信済み
    • Wordfence Free: 2026-08-16に配信予定

修正パッチ詳細

ルート混同修正

コミット: fa72c12879fbfda17d450fc1fd919f698f549f4d
ファイル: wp-includes/rest-api/class-wp-rest-server.php, wp-includes/rest-api.php

変更内容:

再現環境

教育用ラボ環境が公開されている:

VulnCheckの評価によれば、RCEは以下の多段ステップを要する:

  1. バッチエンドポイント経由でルート混同トリガー
  2. SQLi実行(author__not_in経由)
  3. 管理者パスワードハッシュのダンプとクラック
  4. 管理者ログイン
  5. プラグインアップロードによるRCE

参考資料

公式情報源

技術分析

修正コミット

PoC/ラボ

関連ファイル

変更履歴

日付 変更内容
2026-07-19 初版作成 — NVD, GHSA, Beazley, VulnCheck, Rapid7, Cloudflare, Wordfence, Searchlight, SOCRadar, Aikido, 47Cid/wp2shell-labの情報を統合

脆弱性情報(NVD)

影響を受けるバージョン:

概要(日本語): WordPress 6.9.5 より前の 6.9.x および 7.0.2 より前の 7.0.x では、REST API のバッチエンドポイントにおける経路混乱の問題が存在します。この問題は、author__not_in WP_Query SQL インジェクション (CVE-2026-60137) と組み合わさることで、攻撃者による SQL インジェクションおよびリモートコード実行を可能にする可能性があります。

原文: WordPress 6.9.x before 6.9.5 and 7.0.x before 7.0.2 is affected by a REST API batch endpoint route confusion issue which, combined with the author__not_in WP_Query SQL Injection (CVE-2026-60137), could allow an attacker to perform SQL Injection and achieve Remote Code Execution.

VulnCheck KEV

PoC / Exploit

悪用事例

参考リンク