WordPress 7.0.3が未認証XSSを緊急修正、空白入りタグをstrip_tagsが見逃しPHP実行まで繋がる
目次
TL;DR
何が出たか WordPressは2026年8月6日、セキュリティリリース7.0.3を公開した。目玉はログイン画面の未認証リフレクテッドXSS(CVE-2026-64638 / GHSA-52p2-r8wf-jcrf、通称XSS2Shell、CVSS 8.9)
影響範囲 WordPressの全バージョンが影響を受ける。修正は7.0.3に加えて4.7までの各セキュリティ対象ブランチへバックポートされ、7.1 RC2にも含まれる。稼働中のWordPressのほぼ全数が対象になる
未認証で到達できる範囲 連鎖の入口であるXSSはアカウント不要で成立する。ただしPHP実行まで進めるには、ログイン中の管理者を攻撃者のリンクへ誘導してクリックさせるソーシャルエンジニアリングがいる
起点の仕組み 存在しないユーザー名をwp_strip_all_tags()が処理する際、< areaのように<の直後へ空白を挟むとPHPのstrip_tags()は無害な文字列と見なすが、後段のKSESは同じ文字列を実HTMLタグとして復元する。この判定差でタグが残る
発見者 pwn.aiがオープンソースのモデルとマルチエージェントの構成で自動探索し、7月26日に連鎖を再現、翌27日に報告した。8月7日時点で実環境での悪用は確認されていない
やること 7.0.3、または各系列のバックポート版へ即更新する。ダッシュボードの「更新」から適用できる
WordPressプロジェクトは2026年8月6日、セキュリティリリースの7.0.3を公開した。
このリリースは12件の脆弱性修正をまとめている。そのうち公式に認証前(pre-auth)と明記されたのがログイン画面のリフレクテッドXSS(CVE-2026-64638)で、条件が揃えばPHPコードの実行まで繋がる。発見したpwn.aiはこの連鎖を「XSS2Shell」と名付けている。
WordPressは世界のWebサイトの4割超で使われるCMSで、標準構成ではログイン画面(wp-login.php)が公開される。今回の弱点はそのログイン画面の、しかも認証前の入力処理にあるため、影響範囲が広い。
リフレクテッドXSSとは何か
リフレクテッドXSS(反射型クロスサイトスクリプティング)は、攻撃者が仕込んだスクリプトを含むリンクを被害者に踏ませ、そのスクリプトを被害者のブラウザ上で、訪問先サイトの権限で実行させる攻撃だ。
入力した値がそのままページに書き戻される(反射する)箇所があると成立する。今回はログインに失敗したときのエラーメッセージが、入力したユーザー名を書き戻す経路になっていた。
「未認証で到達できる」とは、攻撃者側にログインアカウントがいらないという意味だ。エラーメッセージは誰でも出せるので、XSSを成立させるところまでは前提条件がほとんどない。
空白入りタグをstrip_tagsは見逃し、KSESが拾う
WordPressは存在しないユーザー名を受け取ると、エラーメッセージを組み立てる過程でwp_strip_all_tags()を通す。この関数は内部でPHP標準のstrip_tags()を呼び、HTMLタグを除去する。ところが後段には、投稿本文などで許可済みHTMLを扱うwp_kses_post()(KSESと呼ばれるサニタイザ)が別に走る。
問題は、<の直後に空白があるとき、それをタグとみなすかどうかで両者が食い違う点にある。<の直後に空白を入れた< areaのような文字列を、strip_tags()は「タグではない、ただの文字」と判断して素通りさせる。一方でKSESは同じ< areaを<area>という正規のHTML要素として解釈し直す。pwn.aiの説明では、strip_tags('< area id=test>')は文字列をそのまま返すのに対し、空白のないstrip_tags('<area id=test>')はタグとして除去される。
この差を突くと、除去されるはずの<area>や<div>、<button>といった実要素を、認証なしでログインページへ流し込める。
クリック一回からPHP実行まで
混入したタグは、ここから複数の技法を段階的に繋いでPHP実行へ至る。連鎖の流れは次のとおり。
flowchart TD
A[未認証: 空白入りタグをログイン画面へ注入] --> B[DOMクロバリング<br/>ajaxurlを攻撃者の要素で上書き]
B --> C[REST APIへのJSONP呼び出し<br/>_jsonp=alertで応答をJSに]
C --> D[Same Origin Method Execution<br/>管理者操作を横断呼び出し]
D --> E[アプリケーションパスワードを窃取]
E --> F[unfiltered_htmlで悪意のあるページを公開]
F --> G[プラグインZIPをアップロード]
G --> H[wp-content/plugins内のPHPが直接実行される]
まず、ログインページはパスワードリセットを扱う都合でuser-profile.jsを読み込んでいる。注入した要素がこのスクリプトの自動処理を勝手に走らせる。このとき送られるAJAX要求のURLは、jQueryが参照するajaxurl変数を経由して攻撃者の指定した値に差し替わる。JavaScriptのグローバル変数をDOM要素で上書きして乗っ取るこの手口をDOMクロバリングと呼ぶ。
送信先はWordPressのREST APIに向けられ、_jsonp=alertのようなパラメータでJSONP応答を要求する。応答は/**/alert({...})という実行可能なJavaScriptで返り、jQueryのglobalEval()がWordPress自身のオリジンでこれを走らせる。REST APIが401を返す構成でも、_envelope=1を付けると拒否応答が外側のHTTP 200で包まれ、スクリプトとして処理が続く。
ここから先はSame Origin Method Execution(SOME)という、2022年にPaulos Yibeloが公表した技法を使う。JSONPのコールバックにプロパティの連鎖を書けることを利用し、window.opener.approve.clickのように別ウィンドウの管理操作を横断的に呼び出す。ログイン中の管理者がこの一連を踏むと、アプリケーションパスワード(REST API用の認証情報)が発行され、攻撃者のコールバックへ渡ってしまう。
盗んだ認証情報を使えば、以降は正規のREST APIを普通に呼ぶだけになる。単一サイトの管理者は既定でunfiltered_html権限を持つため、任意のJavaScriptを含むページを公開できる。そのスクリプトがアップロードフォームのnonce(操作ごとに使い捨てるCSRF対策用のトークン)を抜き、/wp-admin/update.php?action=upload-pluginへ攻撃者のZIPを送る。展開されたPHPファイルは/wp-content/plugins/配下でWebから直接叩けるので、これがサーバー上で実行される。
未認証XSSと、その先のRCEを切り分ける
同じCVEの中に「未認証で到達できる部分」と「管理者の操作がいる部分」が同居している。両者はリスクの重さが違う。
| 段階 | 前提条件 | できること |
|---|---|---|
| リフレクテッドXSS | アカウント不要。エラーメッセージを出せれば成立 | ログイン画面上でスクリプトを実行 |
| RCEへの連鎖 | ログイン中の管理者を攻撃者のリンクへ誘導しクリックさせるソーシャルエンジニアリング | アプリケーションパスワード窃取、プラグインアップロード、PHP実行 |
WordPressの勧告も、RCEへの昇格は「攻撃者の制御外の条件」に依存すると位置づけている。つまり管理者が能動的にリンクを踏むという前提がいる。7月に別途出た未認証RCEのwp2shell(CVE-2026-63030など、SQLインジェクションとの連鎖)とは、攻撃が成立する条件が違う。
修正の中身と影響バージョン
7.0.3はwp-includes/user.phpとwp-login.phpにesc_html()、esc_url()、esc_attr()の呼び出しを足した。パーサの食い違いで残った文字列を、ページに書き出す直前でエスケープして塞ぐ修正だ。
影響するバージョンと対応は下表のとおり。
| 項目 | 内容 |
|---|---|
| 識別子 | CVE-2026-64638 / GHSA-52p2-r8wf-jcrf |
| CVSS | 8.9 |
| 影響バージョン | すべてのWordPressバージョン(修正版が提供された対象ブランチは4.7以降) |
| 修正バージョン | 7.0.3(2026年8月6日)、4.7まで遡ってバックポート |
| 併せて公開 | 7.1 RC2 |
| 実環境での悪用 | 8月7日時点で確認なし |
| 公開PoC | pwn.aiが技術詳細を公開 |
自動更新が有効なサイトは順次7.0.3、または各系列のバックポート版へ上がる。手動運用のサイトはダッシュボードの「更新」→「今すぐ更新」から適用できる。4.7より前の系列は修正対象外なので、稼働中なら本体の更新が必要になる。
AIエージェントが探索から連鎖の再現まで回した
今回のもう一つの論点は、発見の経緯だ。pwn.aiはこの脆弱性を、オープンソースのモデルとマルチエージェントの構成で自律的に探索したと説明している。空白入りタグの扱いという単発のバグではなく、DOMクロバリングからSOME、アプリケーションパスワード窃取、プラグインアップロードまでの多段の連鎖を、エージェント側が組み上げて再現した。
タイムラインは、7月26日に連鎖を再現、7月27日にPoC付きで報告、同日WordPressがリスクを認め、8月6日に修正版を公開、8月7日に協調開示という流れだった。pwn.aiによれば、起点となる研究を与えてから連鎖を完成させるまでの作業全体には約4日を要したという。