セキュリティ修正12件。WordPress 7.0.3 が 2026年8月6日に出た。公式リリースは件数を数字で書いておらず「several security fixes」とだけある。一覧の箇条書きを数えると12行あった。いちばん重いのはログイン画面の未認証(pre-auth)反射型 XSS で、PHP コード実行に至る可能性が書かれている(CVE-2026-64638 / GHSA-52p2-r8wf-jcrf)。残りには「Contributor 以上」「Author 以上」「ユーザー登録を有効にしたマルチサイト」といった前提が付く。この前提を読み飛ばすと、急ぐべきものと急がなくていいものが自分の中で混ざる。
目次
12件を「成立に何が要るか」で並べ直す
公式の一覧は報告者への謝辞の形で並んでいて、深刻度順にも影響範囲順にもなっていない。自分のサイトに当てはめるときに要るのは別の軸で、その脆弱性が成立するために攻撃側が何を持っていなければならないか、という並びになる。原文の12行をその軸で組み直したのが下の表だ。
| # | 対象 | 内容 | 成立に必要な前提 |
|---|---|---|---|
| 1 | ログイン画面 | 未認証(pre-auth)の反射型 XSS。PHP コード実行に至る可能性(CVE-2026-64638 / GHSA-52p2-r8wf-jcrf) | 未認証。ログイン画面に到達できること |
| 2 | 投稿(絵文字設定要素を経由) | 格納型 XSS | Contributor 以上 |
| 3 | Post Content ブロック | 格納型 XSS | Contributor 以上 |
| 4 | クイック編集 | 格納型 XSS | Contributor 以上、かつ利用者数の多いサイト(「多い」の閾値は原文に無い) |
| 5 | Post Date ブロック | 格納型 XSS | Contributor 以上 |
| 6 | マルチサイトのユーザー登録 | 権限昇格(利用者が新しいサイトを作成できる) | マルチサイトで、かつユーザー登録が有効 |
| 7 | Latest Comments ブロック | パスワード保護記事のコメントが露出する情報漏えい | 当該ブロックを設置していて、パスワード保護した記事がある(前提は筆者の整理) |
| 8 | 投稿スラッグ | スラッグの列挙 | 原文に権限要件の記載なし |
| 9 | コメントフィード | ノートが露出する情報漏えい | 原文に権限要件の記載なし |
| 10 | CSS | 安全な CSS 属性フィルタを迂回する CSS インジェクション | Author 以上 |
| 11 | メール確認フロー | フローの迂回 | 原文に権限要件の記載なし |
| 12 | URL 検証 | SSRF(link-local レンジへのリクエストが通る) | 原文に権限要件の記載なし |
件数のところで少し引っかかった。公式リリースの本文は several security fixes と書くだけで、総数を数字にしていない。箇条書きの行を数えると12ある。本稿は「原文の箇条書きが12行」という数え方で通す。
バックポートは進行中だ。原文の言い方はこうなっている。
The backports are in progress and will ship as they become ready.
対象は「セキュリティ修正を受け取る資格のある全ブランチ(現時点では 4.7 まで)」とある。かなり古い系列まで手当てが伸びるので、更新を止めている読者にも当たる話になる。届いたかどうかは、自分の版で確かめることになる。
例えば集合住宅で「各戸のドアの鍵に不具合がある」という知らせが来たとする。自分の部屋の鍵の話なら、住人が自分で直せば済む。エントランスのオートロックが壊れているという話なら、住人が何人いるかに関係なく重さが変わる。7.0.3 の12件には、この2種類が混ざっている。
「Contributor 以上」を読み飛ばさない
格納型 XSS の4件には Contributor 以上という前提が付く。読み替えると、自分以外の誰かに投稿権限を配っているかどうかで話が変わる。個人で書いていて管理者アカウントしか無いサイトなら、この行の攻撃者役を引き受ける人がいない。寄稿を受け付けていたり、外部ライターにアカウントを渡していたりするなら、ここが実際の入口になる。
CSS インジェクションの1件だけは Author 以上で、線の引き方が1段違う。寄稿者に配っているのが Contributor だけなら、この行は成立しない。権限の配り方で当たり外れが決まる例になっている。
クイック編集の1件には、もう1つ条件が付いている。原文は on sites with a large number of users と書いていて、利用者数の多いサイトに限る形になっている。何人からが「多い」のかは原文に書かれていない。
マルチサイトの権限昇格は、「マルチサイトである」と「ユーザー登録が有効になっている」の両方が揃って初めて成立する。片方だけでは条件を満たさない。効果は利用者が新しいサイトを作成できるというもので、管理者権限の奪取ではない。
# マルチサイトかどうか(終了コードで判定)
wp core is-installed --network
# 単一サイトのユーザー登録の可否(1 なら開いている)
wp option get users_can_register
# マルチサイトのネットワーク側の登録設定
wp network meta get 1 registration
# 投稿権限を持つアカウントを全件出す
# (Contributor 以上には author / editor / administrator も含まれるので、
# role を個別指定せず一覧で見たほうが取りこぼさない)
wp user list --fields=ID,user_login,roles,user_registered
当サイトがどれに該当するかは、本稿の時点では確かめていない。書けるのは実際に走らせたあとになる。
未認証で成立すると明記されているのは、ログイン画面の1件
pre-auth と付いている以上、この1件はログインしていない相手から成立する。ログイン画面はサイトの外から誰でも到達できるページなので、アカウントを1つも配っていないサイトでも条件が揃う。
ここで一段だけ慎重に読んでおきたい。原文が権限要件を書いていない項目が、ほかに4件ある。投稿スラッグの列挙、コメントフィードのノート露出、メール確認フローの迂回、URL 検証の SSRF。これらは「未認証で成立する」とも「権限が要る」とも書かれていないので、原文からは決められない。表の前提列を「原文に権限要件の記載なし」としてあるのはそのためだ。
「うちは自分しか使っていないから関係ない」と読んだ人に当てはまらないのは、確実にはログイン画面の1件になる。残りの4件は、当たらないと決められるだけの材料が原文に無い。
深刻度をログイン画面の1件に置いているのは筆者の判断で、公式が深刻度を付けているわけではない。一覧の先頭に置かれていることと、PHP コード実行に至る可能性が書かれていることからそう読んだ。
PHP コード実行に至る具体的な経路は、リリースの本文には書かれていない。ここから先は筆者の推測として書く。管理者のブラウザで任意のスクリプトが動く状態を作れたなら、その管理者の権限でできることはひととおりできる。WordPress の管理画面には、テーマ・プラグインのファイル編集と、プラグインの新規追加という、PHP をサーバーに置ける口が最初から用意されている。反射型 XSS が PHP 実行まで届く筋道があるとすれば、この辺りが素直な読み方になる。
この読み方が当たっているなら、更新とは別に今日できることが1つある。管理画面からのファイル編集を閉じることだ。
// wp-config.php
define( 'DISALLOW_FILE_EDIT', true ); // 管理画面のテーマ・プラグインエディタを無効化
define( 'DISALLOW_FILE_MODS', true ); // プラグイン・テーマの追加や更新も禁止(自動更新も止まる)
2行目は副作用が大きい。ファイル改変を全面的に禁止するので、コアの自動更新まで止まる。緊急リリースが自動で当たる仕組みを手放すことになるので、更新経路を別に用意していないサイトで入れる値ではない。筆者は1行目だけを入れる立場を取る。
これで XSS が防げるわけではない。踏まれたあとに PHP を置かれる経路のうち、いちばん手軽な1本を塞ぐだけだ。
自分の環境で何をどう確かめるか(未実測)
今回の記事で書けるのはここまでで、以下は確認の計画になる。実行はまだしていない。
| 確かめること | 手順 | 判定 | 状態 |
|---|---|---|---|
| 現行版 | wp core version |
7.0.3 か、バックポート対象の版に更新されているか | 未実測 |
| 更新の取りこぼし | wp core check-update |
更新候補が残っていないか | 未実測 |
| 自動更新の停止設定 | wp config get で定数を確認 |
停止側の定数が入っていないか | 未実測 |
| 更新チェックの実行 | wp cron event list |
wp_version_check が登録され、実行されているか |
未実測 |
| コアの改ざん | wp core verify-checksums |
既知の例外以外の差分が出ないか | 未実測 |
| 投稿権限の配布状況 | wp user list を全件 |
自分以外に Contributor 以上がいるか。Author 以上がいるか | 未実測 |
| マルチサイトと登録の可否 | wp core is-installed --network / 登録設定の取得 |
権限昇格の前提が揃っているか | 未実測 |
| WAF のソフトルール | 遮断ログを waf_xss の種別で絞って読む |
ログイン画面向けのパターンで行が増えるか | 未実測 |
更新の到達を見る部分は、前回の緊急リリースのときと同じ手順になる。7.0.2 のときの実測では強制自動更新が実際に効いていたので、そのときに使ったコマンドと確認の順番をそのまま使い回せる。同じ手順で今回も当たっているかは、走らせるまで分からない。
wp core version
wp core check-update
# 未定義の定数を取りに行くとエラーで終了する。
# 「エラーで返る=定義されていない=自動更新を止めていない」と読む。
wp config get AUTOMATIC_UPDATER_DISABLED
wp config get WP_AUTO_UPDATE_CORE
wp config get DISALLOW_FILE_MODS
wp cron event list | grep wp_version_check
wp core verify-checksums
WAF が発火するかは、更新の話とは切り離して見る
当サイトは自作の mu-plugin で WAF を動かしていて、XSS らしいパターンを見るソフトルールが入っている。7月29日にルールの迂回を1つ塞いだので、該当パターンが来れば発火しうる状態にはしてある。発火した記録があるかどうかは、まだ見ていない。
確認の段取りはこう考えている。始める前に、ルール本体が enforce で動いているかを先に確かめる。ここを飛ばすと「発火しなかった」を「攻撃が来ていない」と読んでしまう。止まっているルールは何も記録しない。
そのうえで、ログイン画面へのリクエストで遮断ログに waf_xss の行が増えているかを、日時で絞って読む。増えていない場合に取りうる読み方は2つあって、そもそも該当する試行が来ていないのか、ルールがこのパターンを見ていないのかが区別できない。区別するには、自分で無害な目印のパターンを自分のサイトへ投げて、ログに残るかを見ることになる。
# 遮断ログの読み出し(テーブル名・列名は自作プラグインの定義に合わせる)
wp db query "SELECT created_at, rule
FROM <shield のログテーブル>
WHERE rule = 'waf_xss'
ORDER BY created_at DESC LIMIT 50" --skip-column-names
遮断ログにはリクエスト URI を保存する列もあるが、記事には出さない。この値は攻撃側が自由に作れるので、そのまま貼ると攻撃文字列を転載することになる。読むときも、画面へ出す前にエスケープを通す。
試すときに使うパターンも記事に載せない。ログイン画面に効くペイロードの形をそのまま公開すると、読者の役に立つ量より、まだ更新していないサイトへ向かう量のほうが多くなる。載せるのは「ルールが反応したか / しなかったか」の結論と、判定に使った条件までにする。
もう1つ、はっきりさせておきたい前提がある。WAF のソフトルールが発火したとしても、それは更新の代わりにならない。パターン一致で弾く仕組みは、書き方を変えられれば通る。今回のように公式が直ちに更新を推奨しているケースでは、更新が本線で、WAF は更新が届くまでの時間を少し稼ぐ側にいる。mu-plugin をどう点検しているかはmu-plugins の点検手順を書いた記事にまとめてある。
更新そのものが届かない構成になっていないか
緊急リリースで実際に取り残されるのは、更新が届かない設定になっているサイトだと考えている。WordPress.org が強制更新のフラグを立てても、サイト側で自動更新を止めていれば適用されない。次のどれかに当たるサイトは、フラグが立っても更新されない。
AUTOMATIC_UPDATER_DISABLEDを定義しているWP_AUTO_UPDATE_COREをfalseにしているDISALLOW_FILE_MODSでファイル改変を禁止しているauto_update_core_minorフィルタでfalseを返している- WP-Cron を無効化していて(
DISALLOW_WP_CRON)、外部 cron を設定していない
最後の項目が見落とされやすい。定数を入れたまま外部 cron を設定し忘れていると、更新チェックのイベント自体が走らない。
自動更新が効いていなかった場合の手当ては短い。
wp core update --minor
wp core update-db
7.0.3 に固有の回帰報告があるかどうかは調べていない。セキュリティ限定の小さなパッチという性格からすると大きな影響は出にくいはずだが、「報告が見つからない」は「問題がない」の証明にはならない。ステージングを持っているなら先に当てるほうがいい。7.1 が近いこともあって、当てる先の環境は用意しておく価値がある。テーマの互換確認をどう回しているかは7.1 beta3 のときの記事に書いた。
筆者ならこの順で手を付ける
12件を全部同じ重さで扱わない、というのが今回の判断になる。前提条件の付く行は、自分のサイトが条件を満たしているかどうかで扱いが決まる。満たしていない条件を「危険」として自分に貼っても、確認する場所が増えるだけで安全にはならない。
順番はこう考えている。ログイン画面の1件は前提が要らないので、更新が届いているかの確認を最初に置く。次に投稿権限を誰に配っているかを洗い出して、格納型 XSS の4件と CSS インジェクションの1件が自分に当てはまるかを決める。マルチサイトの行は、条件を満たしていなければそこで落とす。原文が権限要件を書いていない4件は、当たらないと決め切れないので、更新の到達で丸ごと面倒を見る側に置く。WAF の遮断ログは最後に見る。更新が当たっていれば、遮断ログを見る目的は「何が飛んで来ていたか」を知ることに変わるからだ。
参考
本稿には自サイトの実測値を一切載せていない。現行版・自動更新の到達状況・WAF の遮断ログはいずれも未実測になる。載せているのは、走らせる手順と、結果をどう判定するかの条件までだ。件数・識別子・前提条件・バックポートの状況は、公開前に公式リリースの原文と突き合わせてある。