CVE-2026-60137

CVE-2026-60137 Vulnerability Report — WordPress Core SQL Injection (WP2Shell Chain)

概要

項目 内容
CVE番号 CVE-2026-60137
公開日 2026-07-17
最終更新 2026-07-18
CVSS v3.1 9.1 (Critical) — CISA-ADP採点
CVSS Vector (CISA-ADP) AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
CVSS Vector (WPScan) 5.9 (Medium) — AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
CWE CWE-89 (SQLインジェクション)
EPSS 【情報不足】NVD未算出時点
CISA KEV 【要確認】2026-07-18時点では未登録(VulnCheckが「early reports of in-the-wild activity」と報告)
GHSA GHSA-fpp7-x2x2-2mjf (Moderate)
関連CVE CVE-2026-63030 (GHSA-ff9f-jf42-662q) — REST APIバッチエンドポイントのルート混同
発見者 TF1T, dtro, haongo (SQLi); Adam Kues at Assetnote / Searchlight Cyber (RCE chain)
ニックネーム "WP2Shell"

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

バージョンブランチ 影響範囲 修正バージョン 影響を受ける脆弱性
WordPress 6.8.x 6.8.0 – 6.8.5 6.8.6 CVE-2026-60137 (SQLi) のみ
WordPress 6.9.x 6.9.0 – 6.9.4 6.9.5 CVE-2026-60137 + CVE-2026-63030 (連鎖RCE)
WordPress 7.0.x 7.0.0 – 7.0.1 7.0.2 CVE-2026-60137 + CVE-2026-63030 (連鎖RCE)
WordPress 7.1 beta 7.1 beta1 7.1 beta2 CVE-2026-60137 + CVE-2026-63030 (連鎖RCE)
WordPress < 6.8 影響なし

技術詳細

脆弱性の概要

CVE-2026-60137は、WordPress CoreのWP_Queryクラスにおけるauthor__not_inパラメータのSQLインジェクション脆弱性である。6.8以降のバージョンで導入された。author__not_inパラメータに信頼できない入力が渡された際、適切なサニタイゼーションが行われず、SQLクエリに直接埋め込まれる。

単独では認証済みユーザーのみが到達可能な制限された影響範囲だが、CVE-2026-63030(REST APIバッチエンドポイントのルート混同)と連鎖することで、認証なしのRemote Code Executionに至る。これが「WP2Shell」と呼ばれる攻撃チェーンである。

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

これは単一脆弱性の評価と連鎖攻撃の評価の違いであり、両方とも正しい文脈で評価されている。

根本原因

脆弱なコードは src/wp-includes/class-wp-query.phpget_posts() メソッド内に存在した。

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

if ( ! empty( $query_vars['author__not_in'] ) ) {
    if ( is_array( $query_vars['author__not_in'] ) ) {
        $query_vars['author__not_in'] = array_unique( array_map( 'absint', $query_vars['author__not_in'] ) );
        sort( $query_vars['author__not_in'] );
    }
    // ⚠️ 配列でない場合のフォールバックパス — ここが脆弱
    $author__not_in = implode( ',', (array) $query_vars['author__not_in'] );
    $where .= " AND {$wpdb->posts}.post_author NOT IN ($author__not_in) ";
}

根本原因: author__not_in が配列の場合は absint() で整数に変換されるが、配列でない値(文字列など)が渡された場合、(array) でキャストした後にそのままSQLクエリに埋め込まれていた。文字列型の入力が整数サニタイゼーションをバイパスし、SQLインジェクションペイロードが直接クエリに挿入される。

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

if ( ! empty( $query_vars['author__not_in'] ) ) {
    // ✅ 常に wp_parse_id_list() で整数リストに強制変換
    $author__not_in_id_list = wp_parse_id_list( $query_vars['author__not_in'] );
    if ( count( $author__not_in_id_list ) > 0 ) {
        sort( $author__not_in_id_list );
        $where .= sprintf(
            " AND {$wpdb->posts}.post_author NOT IN (%s) ",
            implode( ',', $author__not_in_id_list )
        );
    }
    /** キャッシュキー生成の安定性のためにクエリ変数を更新 */
    $query_vars['author__not_in'] = $author__not_in_id_list;
}

修正の要点:

修正コミット詳細

項目 内容
SQLi修正コミット 97b5a75246f6c82fe9d9f0ba492f06d93b602b98
コミットメッセージ "Query: Force author__not_in values to be integers"
変更ファイル数 1ファイル (src/wp-includes/class-wp-query.php)
行数変更 +8行追加, -4行削除
新規関数 なし(既存の wp_parse_id_list() を採用)
RCE修正コミット fa72c12879fbfda17d450fc1fd919f698f549f4d
RCEコミットメッセージ "REST API: sub-requests must always use dispatch."
RCE変更ファイル数 2ファイル

RCE連鎖の仕組み (CVE-2026-63030)

CVE-2026-63030はREST APIのバッチエンドポイント(/wp-json/batch/v1)における「ルート混同」の脆弱性である。攻撃の流れは以下の通り:

  1. 認証バイパス: バッチエンドポイントの内部サブリクエストが誤ったハンドラにルーティングされ、本来は認証が必要なコードパスに認証なしで到達できる
  2. SQLi到達: CVE-2026-63030のルート混同により、CVE-2026-60137のSQLインジェクションが認証なしで実行可能になる
  3. データベース情報窃取: SQLインジェクションで管理者ユーザーのパスワードハッシュをダンプ
  4. クラックとログイン: ハッシュをクラックし、管理者としてログイン
  5. Webshellアップロード: 管理者権限で任意のPHPファイルをアップロード → RCE

VulnCheckによると、「ストレートショットのRCEパスではなく、SQLiでDBからクレデンシャルを窃取→クラック→ログイン→Webshellという多段攻撃である」。

攻撃フロー

[攻撃者] → HTTP POST /wp-json/batch/v1
    ↓
[REST API Batch Endpoint] — CVE-2026-63030 (ルート混同)
    ↓ 認証チェックをバイパス
[WP_Query with author__not_in] — CVE-2026-60137 (SQLi)
    ↓ SQLインジェクション実行
[MySQL] → 管理者パスワードハッシュ返却
    ↓ クラック
[管理者ログイン] → テーマエディタ/メディアアップロードでPHPファイル配置
    ↓
[RCE] — 任意のOSコマンド実行

トリガー条件

条件 CVE-2026-60137 (SQLi単独) WP2Shell Chain (RCE)
バージョン 6.8.0 – 7.0.1 6.9.0 – 7.0.1
認証 必要 (単独の場合) 不要 (連鎖によりバイパス)
プラグイン 不要 (Coreのみ) 不要 (Coreのみ)
author__not_inへの入力 テーマ/プラグインが未信頼入力を渡す必要あり バッチエンドポイント経由で直接到達可能
永続オブジェクトキャッシュ 影響なし 無効な環境で exploitation が容易(Cloudflare分析による)

PoC/Exploitの状況

項目 状況
公開PoC あり — CVE-2026-63030 (RCE chain) 向けに複数のPoCが公開済み
CVE-2026-60137単独PoC 【情報不足】 — SQLi単体でのPoCは確認できず
検知用PoC あり — Senanfurkan/wordpress-cve-2026-63030 (Detection PoC)
Exploit成熟度 PoC → Weaponization進行中
実利用 PatchStackが2026-07-17 19:00 ET頃に攻撃を観測報告(詳細不明)
Searchlight Checker wp2shell.com — 脆弱性チェック用公開ツール

⚠️ 注意: 複数のフルエクスプロイトPoCがGitHubで公開されているが、実行は自己責任。VulnCheckは「early reports of in-the-wild activity」を確認しており、パッチ適用が最優先。

実被害・インシデント

検出方法

ブラックボックステスト

WordPressバージョン確認

# レスポンスヘッダーまたはジェネレーターメタタグでバージョン確認
curl -sI https://target.com | grep -i "x-powered-by\|generator"
curl -s https://target.com | grep -oP 'content="WordPress [^"]*"'

SQLiテスト (注意: 本番環境で実行する場合は許可を得ること)

# author__not_inパラメータを含むREST APIリクエストの監視
# WAFログで以下のパターンを検知:
# - /wp-json/batch/v1 への異常なPOSTリクエスト
# - author__not_in に文字列・特殊文字が含まれるリクエスト

WAFルール (Cloudflare)

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

ホワイトボックステスト

ソースコード上の脆弱パターン

# 脆弱バージョンのコードで grep
grep -rn "author__not_in" wp-includes/class-wp-query.php
# 修正前: (array) $query_vars['author__not_in'] が直接SQLに埋め込まれているか確認
# 修正後: wp_parse_id_list() を使用しているか確認

修正確認

# 修正版で確認すべきコードパターン:
# wp_parse_id_list( $query_vars['author__not_in'] ) が存在するか
grep -n "wp_parse_id_list.*author__not_in" wp-includes/class-wp-query.php

対策

恒久的対策

現在のバージョン 推奨アクション 修正バージョン
6.8.x 6.8.6に更新 6.8.6 (SQLi修正のみ)
6.9.x 6.9.5に更新 6.9.5 (SQLi + RCE修正)
7.0.x 7.0.2に更新 7.0.2 (SQLi + RCE修正)
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」で匿名アクセスを制限
  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に配信予定
  4. データベースアクセスログの監視:

    • 不審なSQLクエリパターンを監視
    • author__not_in に文字列・特殊文字が含まれるクエリをアラート

修正パッチ詳細

SQLi修正 (CVE-2026-60137)

コミット: 97b5a75246f6c82fe9d9f0ba492f06d93b602b98
ファイル: src/wp-includes/class-wp-query.php

変更内容: author__not_in の処理ロジックを全面的に書き換え。配列・非配列を問わず wp_parse_id_list() で整数リストに強制変換。sprintf でSQLを組み立て。

RCE修正 (CVE-2026-63030)

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

変更内容:

これにより、バッチエンドポイントのサブリクエストが誤ってトップレベルのRESTルートとして処理されることを防ぐ。

再現環境

現時点で公開されたDockerベースの再現環境は確認されていない。

VulnCheckの評価によれば、RCEは「ストレートショット」ではなく、以下の多段ステップを要する:

  1. バッチエンドポイント経由でSQLi実行
  2. 管理者パスワードハッシュのダンプとクラック
  3. 管理者ログイン
  4. Webshellアップロード

インストールされたサードパーティプラグインによっては、初期アクセスクリークからのRCEパスが追加で存在する可能性がある。

参考資料

公式情報源

技術分析

修正コミット

PoC

関連ファイル

変更履歴

日付 変更内容
2026-07-19 初版作成 — NVD, GHSA, Beazley, VulnCheck, Cloudflare, Wordfence, Searchlightの情報を統合

脆弱性情報(NVD)

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

原文: WordPress 6.8.x before 6.8.6, 6.9.x before 6.9.5, and 7.0.x before 7.0.2 does not properly sanitise the author__not_in parameter of WP_Query, which could allow SQL Injection when a plugin or theme passes untrusted input to the parameter.

VulnCheck KEV

PoC / Exploit

悪用事例

参考リンク