淡い灰青色の背景に描かれた、フラットなベクター幾何学による生成的な抽象イラスト。左側では、同一の小さな輪郭正方形が密集したグリッドが、堅牢化されたコードベースを表している。最も端にある一つの正方形は琥珀色で描かれ、極細の経路を放つ。その経路はかすかな垂直境界を越え、その後、二本の平行な極細線に分かれて、右側の細い接続線とノードによるより疎なネットワークを縫うように通り、半透明のシアン色の淡い面の上にある小さな単一の塗りつぶし琥珀色ノードへ収束する。短くかすかな破線が、二本の接続線が隣接するものと位置ずれを起こしている箇所を示している。テキスト、数字、人物、ブランドマーク、組織ロゴは一切現れない。OrcaRouterのロゴが右下隅に合成されている。
AI Safety Incidents

wp2shell:25ドルで10時間で発見された、標準WordPressのRCE

著者

Rowan Sterling

公開日

最新モデル · 20すべてのモデルを見る →
ベンチマーク:Artificial Analysis · 毎日更新
すべての記事に戻る

2026年7月17日、Searchlight Cyber は wp2shell を公開した。これは WordPress コアにおける認証前のリモートコード実行チェーンで、プラグインもテーマもログインも不要である。標準インストールに対して匿名リクエストを送るだけで十分だ。同社のアドバイザリは「この攻撃には前提条件がなく、プラグインのない WordPress の標準インストールで匿名ユーザーが悪用できる」と述べている。このチェーンは2つのバグを組み合わせている。CVE-2026-63030 は WordPress REST API のバッチエンドポイントにおけるルート混同の脆弱性で、プロジェクトのアドバイザリは重大と分類している。また CVE-2026-60137 は SQL インジェクションであり、その対象は author__not_in パラメータ(WP_Query の)で、中程度と分類している。WordPress は同日に WordPress 7.0.2 をリリースし、プロジェクトのアドバイザリは WordPress 6.9.5、WordPress 6.8.6、WordPress 7.1 beta2 にも同じ修正が含まれると列挙している。Searchlight は 5 億を超える WordPress サイトの推定数を引用している。このチェーンの背後にいる研究者 Adam Kues は、OpenAI が数学の問題向けに公開したプロンプトを基にした GPT-5.6 Sol Ultra の実行から生まれたと述べている。最大 4 エージェント、探索に少なくとも 6 時間、エスカレーションにさらに約 4 時間、モデル使用料はおよそ 25 ドルだった。この記録は研究上の知見として登録されている。アーカイブ独自の尺度で高重大度、A グレードの確信度、実世界での被害記録なし、日付は単一日である。そして Orca AI Incident Archiveは、その下に一次資料をリンクした形でこれを収載している。

開示は調整された形で行われた。Searchlightは7月17日に攻撃手法の詳細を伏せ、防御側に週末をアップグレードに充てる時間を与えた。Kuesは7月20日に完全な技術的説明を公開した。その時点で、連鎖型エクスプロイトはすでに独立して再現されていた。Searchlightによれば、CalifとHacktronは、他の概念実証(PoC)がGitHubに出現する前に完全な攻撃チェーンを再構築した。WordPress自身が発行した2件のセキュリティアドバイザリは同じ修正済みバージョンを示しており、CISAは7月21日に両方のCVEをKnown Exploited Vulnerabilitiesカタログに追加した。

2つのバグと、足並みがずれる配列

このエントリーポイントはミスではなく機能です。WordPress 5.6 は2020年にバッチエンドポイントを導入し、クライアントが1つのHTTPリクエスト内で複数の仮想RESTリクエストを送信できるようにしました。たとえば、複数の投稿のタイトルを一度に変更する場合です。このエンドポイントは、呼び出し元が認証済みかどうかに関係なく到達可能であり、各サブリクエストは呼び出し元が提供した認証をそのまま引き継ぎます。WordPress RESTルートへの直接リクエストは、4段階のパイプラインを実行します。必須パラメータと有効なパラメータを確認し、それらをサニタイズし、権限コールバックを実行し、その後でエンドポイントコールバックを実行します。エンドポイントは型の前提をそのパイプラインに依存しています。つまり、投稿IDは整数であり、タイトルは文字列であるということです。

バッチ API はパイプラインを 2 つに分割し、1 つのループで各サブリクエストを検証し、2 つ目のループでそれらを実行します。また、2 つの配列を保持しており、$matches と $validation の要素はインデックスごとに一致するように意図されています。class-wp-rest-server.php では、Kues が説明するように、それ自体が WordPress エラーであるサブリクエストが $validation に追加され、その後 continue に到達し、$matches に追加する行をスキップします。その時点から、すべてのマッチは 1 つ後ろにずれます。実行ループは、あるインデックスのサブリクエストを、そのインデックスに記録された検証と組み合わせますが、ハンドラーは別のルートにマッチしています。つまり、パラメーターはあるエンドポイントのルールに照らしてチェックされ、その後、別のエンドポイントのコードによって実行されます。

それこそが、一見普通のリストパラメータをインジェクションに変えるものです。posts コレクションルートは、その公開 author_exclude 引数を author__not_in にマップします。値が配列の場合、WordPress は absint をすべての要素に適用して並べ替えます。値がスカラーの場合は、そのまま SQL フラグメントに連結され、その結果は NOT IN ($author__not_in) になります。次のような文字列:0) OR 1=1 -- は、それによってクエリテキストに入り込みます。通常どおり呼び出された場合、ルートはそれを拒否するはずです。なぜなら author_exclude は整数の配列でなければならないからです。同期がずれたバッチ呼び出しこそが、文字列を通過させてしまうものです。

2つの障害が残っていたが、どちらもこのトリックを入れ子にすることで解決された。バッチAPIはGETリクエストを拒否し、インジェクションはGETルート上に存在する。また、リクエストメソッドの検証自体がパラメータ検証として実装されており、同じ同期ずれによって回避できる。Kuesが公開したペイロードは、メソッドチェックに同期ずれを起こすために不正な外側のサブリクエストを送り、次に、2番目のサブリクエストが悪意のあるauthor_excludeを、それを検証しないハンドラに対して運ぶ内側のバッチを送り、最後にそれを実行するGETを送る。UNIONベースのインジェクションは、通常の投稿と同じ形をした行の中に任意のデータベース値を返す。

A self-built HTML card headed 'wp2shell: what is affected and what fixes it', laying out two columns of version ranges as a scannable table. The left column, labelled CVE-2026-63030, batch route confusion, critical, CVSS 9.8, lists affected WordPress 6.9.0 to 6.9.4 and 7.0.0 to 7.0.1, fixed in WordPress 6.9.5 and WordPress 7.0.2. The right column, labelled CVE-2026-60137, author__not_in SQL injection, moderate, CVSS 5.9, lists affected WordPress 6.8.0 to 6.8.5, 6.9.0 to 6.9.4 and 7.0.0 to 7.0.1, fixed in WordPress 6.8.6, WordPress 6.9.5 and WordPress 7.0.2. A footer strip notes that 7.1 beta2 also carries the fixes and that the full chain needs WordPress 6.9 or later. Small print at the bottom credits the version ranges to the two WordPress security advisories and the scores to the WPScan-assigned CVSS vectors.

モデル実行:数学のプロンプトをコードベースに向けた場合

Kuesはプロンプトを一から書いたわけではなかった。OpenAIはCycle Double Cover予想に取り組む際に使用したプロンプトを公開しており、Kuesは、モデルが最近その予想を解決したと読んだこと、そしてセキュリティコミュニティでは誰もそのプロンプトについて話しているようには見えなかったことを書いていた。彼の論拠は、それが難しい数学に十分なほど良ければ、セキュリティ研究にもおそらく十分だろうというものだった。彼はそれを改変し、WordPressに向けた。

セットアップは意図的に狭く設定されていた。彼は最新の安定版WordPressリリースをmain/というディレクトリにクローンし、その.gitディレクトリを削除した。そしてモデルに対し、変更履歴、git履歴、公開インターネットを使ってコードをパッチ済みバージョンと差分比較しないよう指示した——彼が述べた理由は、新規の脆弱性発見において履歴やウェブを参照するのはトークンの無駄だからである。空のthird_party/ディレクトリが用意され、チェーンにWordPressの下層ライブラリのバグが必要とモデルが判断した場合に、PHPやMySQLのソースなどの依存関係をクローンできるようにした。タスクは、MySQL上の典型的な本番デプロイにおける認証前RCEとして指定され、最大4つのエージェントと少なくとも6時間が与えられた。Kuesは、モデルがそうしないと「ズルをする」——極端に起こりにくい設定オプションを選ぶか、攻撃者が決して達成できない前提条件を捏造する——ため、設定要件を明示していると書いた。

実行中の出力で返ってきたのは、認証前のSQLインジェクションだという主張だった。クースはそれを疑った。WordPressは史上最も厳しく監査されてきた対象の一つであり、その10年間に意味のある認証前脆弱性はなかった、と彼は書いた。彼はリモートサーバーに標準のWordPressインスタンスをインストールし、管理者のメールアドレスを窃取するようモデルに依頼した。数分以内に、モデルはインスタンスのセットアップに使ったアドレスを出力した。次に彼は、その読み取り専用インジェクションを昇格できるかと尋ね、約4時間後、モデルは可能だと答えた — 管理者権限への昇格が、パスワードを一切解読せず、オフライン計算も行わずに。

彼自身のコスト計算では、10時間強で生成されたエクスプロイトに対して、週あたりの利用枠の50%、200ドルのサブスクリプションに按分するとおよそ25ドルだった。人間の部分は無料ではなかった——Kuesは翌日を費やしてモデルが何をしたのかを解きほぐし、ポストエクスプロイテーション作業は、生成にかかった時間よりも理解にずっと長くかかったと書いている。彼の結論は異例なほど率直で、限定的な範囲にとどまっている。「一般論は述べないが、AIなしでセキュリティ研究者がこのエクスプロイト・チェーンを10時間で発見し完了できたはずだと言える者は一人もいない、と完全な自信を持って言える」。

読み取り専用のSELECTから管理者へ

最も重要なのは記録のうち昇格の部分だ。そこが、データベースの読み取りがサーバーの制御へと変わった地点だからだ。Kuesの説明では、それを6つの手順の連続として展開しており、各手順はありふれたWordPressの機能を別の機能に対して用いている。

まず、メモリ内の投稿キャッシュを汚染します。WordPress は WP_Post オブジェクトのリクエスト単位のキャッシュを保持しているため、同一リクエスト内で複数回参照される同じ投稿はデータベースへの往復を1回で済みます。SQLインジェクションによって投稿を偽造できるため、攻撃者はキャッシュされる内容を完全に制御できますが、偽造された投稿はデータベース内の行ではなく、キャッシュはリクエストとともに消えます。

次に、偽造された投稿を実際の行に変えます。WordPress の埋め込み機能は、解決済みの埋め込みをデータベース内に投稿としてキャッシュします。その投稿タイプは oembed_cache。ローカル投稿を相対パスで埋め込むと、次のように [embed]/?p=S[/embed]、WordPress は HTTP フェッチをスキップし、参照された投稿が存在するかどうかを一切確認しないため、行が作成されます。クエリ文字列トークンが異なるこのような埋め込みを 3 つ行うと、3 つの異なるキャッシュハッシュが生成され、これにより攻撃者は作業に使える複数の行を取得できます。

第三に、固定されたままの唯一のフィールドを回避します。投稿のメモリ内バージョンとデータベースバージョンが一致しない場合、WordPress は、明示的に設定する呼び出しでそれらを整合させます。その設定対象はpost_contentで、埋め込み出力から取得されます。投稿に関するすべては、その内容を除いて攻撃者によって制御されています。その内容こそが、まさにcustomize_changesetが保留中のテーマとサイトの変更の JSON を保存するために使用するフィールドです。

第四に、循環ガジェットです。投稿には親があり、WordPress は循環を拒否します:wp_insert_post_parent フィルターはツリーを上へたどり、ループを見つけると、post_parent をゼロに設定する更新を呼び出します。その呼び出しは post_content を上書きしないため、インメモリで捏造されたバージョンはリコンシリエーションを経ても生き残ります。つまり、JSON が無傷のまま残ったチェンジセットが、実在する行に支えられているのです。

第5に、管理者の権限を借用します。ステータス上は将来の実行予定となっているのに、日付が過去であるチェンジセットは即座に適用されます。そのJSON内の各エントリは user_id を指定しており、Kuesのチェーン内のエントリは user_id 1(管理者)を指定しているため、WordPressは変更を適用するために一時的にそのIDを採用します。最初の変更は、次の項目に対する一見無害な更新です:nav_menus_created_posts。

第 6 に、その識別情報としてリクエストを再生します。投稿を公開すると、動的に名前が付けられたアクションが発火します、{status}_{post_type}。投稿は捏造されているため、そのステータスとタイプは任意の値になり得ます — 次を含みます: parse と request。これにより、parse_request フックが発生し、借用した管理者の識別情報がまだ有効な間に、リクエストパイプラインを先頭から再起動します。元のバッチリクエストには、新しい管理者を作成するサブリクエストが含まれていました。これはゲストとしての最初のパスでは失敗し、再生時には成功します。そこから攻撃者はその新しいアカウントとしてログインし、ZIP ファイルからバックドアプラグインをアップロードします。これがコード実行になります。

A self-built HTML card titled 'Six moves from a SELECT to a shell', drawn as six numbered panels in two columns of three. Panel 1, fabricate posts: a UNION injection over the posts collection returns attacker-shaped rows, which WordPress stores in its per-request WP_Post cache. Panel 2, seed embed rows: embedding a local post by relative path writes stored oembed_cache rows, and WordPress never checks that the referenced post exists. Panel 3, content stays fixed: reconciling memory against the database overwrites post_content, the one field a changeset needs for its JSON. Panel 4, break the cycle check: a fabricated parent loop triggers WordPress's own cycle fix, an update that resets post_parent without touching post_content. Panel 5, borrow admin authority: a past-dated customize_changeset whose entries carry user_id 1 is applied as the administrator. Panel 6, replay as admin: a fabricated post with status parse and type request fires the parse_request hook, rerunning the batch so the admin-creation subrequest succeeds. A dark footer bar states that the new administrator then logs in and uploads a backdoor plugin from a ZIP file, which is code execution. No photographs, logos or personal names appear.

この手法には条件が付いている。The Hacker NewsはCloudflareを引用し、CVE-2026-63030によるリモートコード実行は永続オブジェクトキャッシュが使用されていない場合にのみ成立すると報じた。インジェクション自体はWordPress 6.8から存在するが、完全な攻撃チェーンには6.9以降が必要だ。標準のインストールには永続オブジェクトキャッシュがない。そのため、Searchlightの「前提条件なし」という表現とCloudflareの限定条件は、同じデフォルトのケースを異なる方向から説明している。

一次資料が明らかにするもの

WordPress自身のアドバイザリは最も強力な裏付けである。なぜなら、これらはベンダーがその仕組みを認め、修正を出荷していることを示すものだからだ。GHSA-ff9f-jf42-662qは重大(critical)と評価され、WordPress 6.9以降におけるREST APIのバッチルート混同という弱点について説明しており、これはインジェクションと組み合わさってコード実行に至るもので、AssetnoteおよびSearchlight CyberのAdam Kuesにクレジットを付与している。GHSA-fpp7-x2x2-2mjfは中程度(moderate)と評価され、次のものを説明している:author__not_inインジェクション(WordPress 6.8以降)について述べ、両方の問題がWordPress 7.0.2、WordPress 6.9.5、WordPress 6.8.6、およびWordPress 7.1 beta2で修正されているとしている。2つのCVEに関するNVDの記録は、NISTではなくWPScan CNAによって採点されており、CVE-2026-63030には9.8、ベクトルAV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:Hを、CVE-2026-60137には5.9、ベクトルAV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:Nを付けている。前者はネットワーク到達可能で特権を必要としないバグであり、後者は高い攻撃複雑性を必要とし、影響は機密性のみにとどまる。アーカイブ自身のこの項目の重大度フィールドは高(high)と記されている一方、WordPressはバッチの脆弱性を重大(critical)とラベル付けしている。この2つは、攻撃チェーン全体と単一コンポーネントに適用された別個の尺度であり、バグ自体についての不一致ではない。

CISAのカタログ項目は、NVDの拡充フィールドに反映されているとおり、2026年7月21日に追加され、修復期限はCVE-2026-63030が7月24日、CVE-2026-60137が8月4日でした。CISAは1つ目を「WordPress Core Interpretation Conflict Vulnerability」、2つ目を「WordPress Core SQL Injection Vulnerability」と呼んでいます。Searchlightはまた、運用者がスキャナのシグネチャを待たずにインスタンスをテストできるよう、wp2shell.comで公開チェッカーを公開しました。

独立した再現はSearchlight自身によって記録されているため、これは第三者の証言ではなく、第三者に関する主張である。7月20日の記事によれば、CalifとHacktronは、他の実証コード(proof of concept)がGitHubに登場する前に、攻撃チェーン全体を再構築した。独立して検証可能なのはその効果であり、すなわち数日以内に現れた実証コード、悪用トラフィック、ベンダーのテレメトリで、以下で詳述する。

A self-built HTML card titled 'Four days from advisory to catalog', drawn as a vertical timeline of five dated rows against a blue rule, the last row in amber. 17 July 2026, disclosure: Searchlight Cyber publishes the wp2shell advisory with the mechanics withheld and WordPress releases 7.0.2, with 6.9.5, 6.8.6 and 7.1 beta2 listed as carrying the same fixes. 18 July 2026, first exploitation: watchTowr reports that by the early hours of Saturday morning UTC successful exploitation was already well underway, initially to exfiltrate hashed credentials. 20 July 2026, full account: Kues publishes the GPT-5.6 Sol Ultra write-up while Wiz publishes an in-the-wild report, with 60 percent of WordPress-using organisations holding a vulnerable instance and 25 percent exposed to the internet, falling to 50 and 10 percent within 24 hours. 21 July 2026, CISA KEV: both CVEs enter the Known Exploited Vulnerabilities catalog. 24 July and 4 August, remediation due: CISA's two deadlines. A source line at the bottom names the WordPress advisories, The Hacker News for watchTowr, Wiz, and the cisaExploitAdd and cisaActionDue fields in NVD records. No photographs, logos or personal names appear.

何が主張されているが、立証されていないのか

1件のインジェクションに対する2件のクレジットは、公開記録上、整合しない。WordPressのCVE-2026-60137に関するアドバイザリは、この脆弱性が「TF1T、dtro、haongoがチームとして発見し、責任ある形で開示した」と述べている。Searchlightの説明は、同社のモデル実行で明らかになったものと同じ認証前インジェクションを提示しており、そのチームには言及していない。WordPressのアドバイザリは、Kuesの功績をバッチルートの混同についてのみ挙げており、モデルには言及していない。どちらの文書もこの重複を説明しておらず、本稿が確認した範囲では、それを解消するものは何もない。両者が同一のバグに対する独立した発見であった可能性は排除されておらず、一方の報告が後日の再発見である可能性も立証されていない。公開記録はこれを裁定しておらず、本記事も同様である。

Searchlightの7月20日の投稿の見出しの数字は、その本文によって裏付けられていない。見出しには「エクスプロイト仲介業者はWordPress RCEに50万ドルを支払う。GPT5.6 Sol Ultraと25ドルで一つ見つけた」とある。本文は25ドルと10時間を具体的に記述しているが、仲介業者名、オファー、やり取り、50万ドルという数字の出典は一切示していない。本記事に関して見つかった独立した報道は、wp2shellに対して支払われた、または提示された価格を裏付けていない。50万ドルは見出しの演出として読み、確立された市場価格として読むべきではない。

アーカイブ項目自体の範囲は、それを取り巻くストーリーよりも狭い。この項目は開示日の研究結果を記録し、現実世界での被害がないことを示し、日付は2026年7月17日という単一の日に限定されている。これは、その後何も起きなかったと主張するものではない。勧告から数時間以内に悪用トラフィックが報告され、CISAは4日後に両方のCVEをカタログに登録した。このフラグが対象とするのは、項目が記述している内容、すなわち発見と協調的開示であり、その後の悪用は以下で他の当事者によって独自の証拠に基づき文書化されている。

アドバイザリ公開後の悪用

watchTowrの主任セキュリティ研究者であるJake KnottはThe Hacker Newsに対し、「土曜日の早朝(UTC)の時点で、すでに悪用が本格的に進んでおり、当初は公開されているエクスプロイトコードを用いてハッシュ化された認証情報を窃取し、追加の詳細が公開されるとリモートコード実行が続いた」と語った。同じ報告書は、スイス、ドイツ、英国、インドネシア、リトアニア、オランダ、シンガポールの13個の固有IPアドレスをCVE-2026-63030の悪用と関連付けたKEVIntelのテレメトリを引用し、KEVIntel創設者のRyan Dewhurstの「リクエストは公開されている概念実証と一致しており、ブラインド、UNIONベース、ブールベースのペイロードがすべて使用された」という発言を引用している。

Wizの研究者Shahar DorfmanとGili Tikochinskiは、7月20日の発表で、その規模を数値化した。WordPressを使用している組織の60%は、CVEが公開された時点で少なくとも1つの脆弱なインスタンスを抱えており、25%は脆弱なサーバーをインターネットに公開していた。パッチ適用が始まると、24時間以内に50%と10%に低下した。彼らは、管理者インストーラー経由の悪意あるプラグインアップロード、usersエンドポイントに対するユーザー列挙、ローカルファイルインクルージョン試行(対象はwp-config)を記録し、HTTP 200を返す管理パネルへのアクセス——偵察ではなくログイン成功の兆候——も確認した。彼らが発見したマルウェアは、最小限の1行PHPバックドアから、CMSmapという正規のWordPressセキュリティプラグインを装った150 KBのウェブシェルまで多岐にわたり、ファイル管理、データベースアクセス、ポートスキャン、権限昇格モジュールを備えていた。

Wizはまた、結論付けられることの限界についても記録している。侵害後の活動を伴わない大量スキャンは一般的であり、機会主義的な大規模スキャンや正当なセキュリティスキャンと整合的だった。また同社は、横展開やデータの外部送信を特定していないと述べた。これはあるベンダーのテレメトリーが示した内容についての陈述であり、何も持ち出されなかったという認定ではない。

その後、何が変わり、何が未解決のままだったのか

運用担当者にとって、対応の道筋は短かった。WordPress 7.0.2、WordPress 6.9.5、または WordPress 6.8.6 への更新が修正策となる。Searchlight の緊急代替策は、すぐに更新できないサイト向けに、バッチ API への匿名アクセスをブロックすることだった。つまり、REST API への匿名アクセスを完全にブロックするプラグインをインストールするか、/wp-json/batch/v1 と ?rest_route=/batch/v1 をウェブアプリケーションファイアウォールでブロックするかだ。同社は、どちらもサイトの正当な利用に影響し得るため、更新が適用されるまでの一時措置として扱うべきだと警告した。wp2shell.com の公開チェッカーは、インスタンスを直接テストする。CISA のカタログ項目はコンプライアンス期限を追加した。CVE-2026-63030 は 7 月 24 日まで、CVE-2026-60137 は 8 月 4 日までの是正である。

研究上の問いのうち、未解決の部分は、モデルが実際に何を貢献したのかをその運用者と比べて明らかにすることだ。Kuesは役割分担について正確に述べている。モデルは約10時間でチェーンを生成し、それを理解するのに彼は生成にかかった時間より長くかかった。彼は一般的な主張を避け、10時間の成果は人間が独力では到達できなかった、とだけ述べる。プロンプト自体は秘密ではない。OpenAIが公開したものに由来し、Searchlightは記事でその構造を再現した。バージョン履歴を無視する指示や、エクスプロイトが典型的な本番構成で機能するという要件も含まれていた。そのレシピが他のコードベースにも移転するかどうかこそ、Kuesが答えていないと言う問いであり、2回目の実行は公開されていない。

したがって、記録が未解明のまま残している点は、範囲こそ狭いものの重大である。すなわち、功績を認められた二つの当事者のうちどちらが先にインジェクションを発見したのか、ブローカーの誰かが実際に見出しの金額を支払ったのか、そしてWizが観測したウェブシェルが、到達したサイトから実際に何を(あるいは何も)持ち出したのか。最後の点について公開されている発言はWizのものだけであり、横方向の移動やデータの外部流出は確認していないという内容だ——一つの視点から見た証拠の不在にすぎず、そうしたものとして提示されている。