WordPressのサイトを管理型のホスティングに載せていると、PHPの更新は提供元の仕事になり、利用者は修正を自分で当てられません。2026年10月21日の夜、認証なしで遠隔からコードを実行されうるPHPの脆弱性2件の修正版が出たとき、私たちが運用を手伝っているクライアントのサイト3つは、まさにこの形で動いていました。修正版の公開から、3サイトのPHPが 8.3.35 から 8.3.36 に変わったのを私たちが確かめるまで、約2時間かかりました。
この記事は、10月21〜22日に私たち(グリームハブの開発チーム)が行ったセキュリティ対応を3回に分けて記録する特集の第1回です。第2回はeMudhraの中間CAの侵害と開発端末の点検、第3回はNode.js 22.23.4への社内の一括更新を扱います。
ここでは、PHPを自分で管理していない立場で何を確かめ、どこまで判断できたかを、時刻つきの記録と、そのとき開いた公式の資料をもとにまとめます。脆弱性の中身、系列ごとの修正版、すぐに上げられない場合の緩和策はPHPに未認証RCEの脆弱性2件 上げる版と緩和策の限界で解説しているので、ここでは繰り返しません。クライアントの名前やサイトの場所は伏せています。
修正版が出る前に、対象と確かめ方を決めた
10月20日、php.net は、重大な脆弱性2件(どちらも CVSS v4.0 で 9.2)を直すリリースを、10月21日 14:00 UTC(日本時間 23:00)に出すと予告しました。詳細は公開まで伏せられていたため、21日の日中は、対象の洗い出しと、更新の前後を比べるための記録づくりに使いました。
| 対象 | PHPを更新するのは | 私たちが確かめられること |
|---|---|---|
| 管理型のWordPressホスティングで公開中のサイト3つ | ホスティングの提供元 | 管理画面に出るPHPの版、ページの動作 |
| CMSのクラウド版で構築中のサイト(公開前の検証環境。本番環境は翌日に構築する予定) | CMSの提供元 | 提供元からの案内の内容と、止められた場合に影響が出る範囲 |
| 開発機でクライアントのサイトを動かすDockerの環境 | 私たち | 使っているイメージと、どこから接続できるか |
末尾の番号まで見える場所を探す
管理型ホスティングの3サイトは、応答ヘッダーにPHPの版が出ないため、外からは版が分かりません。ホスティングの管理画面のサーバー設定には「8.3」のような系列までしか出ません。末尾の番号まで見られたのは、WordPressの管理画面の「ツール > サイトヘルス > 情報 > サーバー」でした。WordPress.org の告知も、この画面でPHPの版を確かめるよう案内しています。
21日の夕方の時点で、3サイトとも 8.3.35 で、PHPの動かし方(Server API)は fpm-fcgi でした。修正版の番号はまだ公表されていなかったため、この数字を記録しておき、公開後に比べることにしました。
更新前のページの動きを記録する
PHPが更新されたあとにサイトの動きが変わっていないかを比べるため、Pythonの標準ライブラリだけで動く小さな確認ツールを作り、21日 16:35 に更新前の記録を取りました。対象は3サイトの24ページで、トップ、記事やお知らせの詳細、検索、REST API、フィードなどを含めています。
比べるのは次の5点です。1件でも差があれば、要確認として表示し、終了コード 1 を返します。
- 状態コード
- PHPのエラー文言(「Fatal error」「重大なエラーがありました」など)があるか
- ページのタイトル
- サイズ(20%を超える変化)
- 応答時間(3倍を超える遅れ)
工夫したのはキャッシュの避け方です。キャッシュ済みのページは、裏のPHPが壊れていても 200 を返します。そこで、毎回クエリを付けて、PHPを実際に通すようにしました。ツールからの抜粋です。
# キャッシュ済みのページは PHP が壊れていても 200 を返すため、毎回クエリを変えて PHP を通す
def bust(url):
parts = urllib.parse.urlsplit(url)
query = urllib.parse.parse_qsl(parts.query, keep_blank_values=True)
query.append(("_phpchk", str(int(time.time() * 1000))))
path = urllib.parse.quote(parts.path, safe="/%")
return urllib.parse.urlunsplit(
(parts.scheme, parts.netloc, path, urllib.parse.urlencode(query), "")
)
更新前の記録では、24ページすべてが 200 で、エラー文言はありませんでした。応答ヘッダーからも、24ページすべてがキャッシュを通らず、PHPが作った応答だったことを確かめています。
自分たちの開発機は、待たずに止める
開発機も見直しました。クライアントのサイトを手元で動かすDockerの環境が2つ、公式のWordPressのイメージ(ApacheとPHPを一体で動かす mod_php の構成、PHP 8.3.28)で動いていて、同じネットワークの他の端末から接続できる設定のままでした。公式の告知が最も危険とした構成が、この mod_php です。外部には公開していませんでしたが、21日 22:50 に WordPress と phpMyAdmin のコンテナを止めました。
管理型ホスティングでは、しばらく 8.3.35 のままだった
修正版は予告の 23:00 より早く公開されました。GitHub の php/php-src のアドバイザリ2件の公開は 22:34 で、8.3 系の修正版は 8.3.36 です。そこから私たちが見たことを、時刻順に並べます(日本時間)。
| 日時 | 私たちが見たこと |
|---|---|
| 21日 夕方 | サイトヘルスで3サイトとも 8.3.35。16:35 に確認ツールで更新前を記録 |
| 21日 22:34 | アドバイザリ2件が公開(8.3 系の修正版は 8.3.36) |
| 21日 22:47 | 3サイトとも 8.3.35 のまま。確認ツールの比較で差なし |
| 21日 23:00 | 提供元のステータスページに「サイトは保護されている」とする投稿 |
| 21日 23:06 | 8.3.35 のまま。確認ツールの比較で差なし |
| 21日 23:32〜23:37 | キャッシュを通らない応答がすべて 500。23:37:53 に復旧を確認 |
| 21日 23:38〜23:39 | 8.3.35 のまま。確認ツールの比較で差なし |
| 22日 0:25〜0:27 | 3サイトとも 8.3.36。確認ツールの比較で差なし |
「保護済み」の理由は書かれていなかった
23:00 付で、ホスティングの提供元のステータスページに、PHPの重大なセキュリティ更新についての投稿が出ました。要旨は「今日のPHPの更新は把握しており、サイトは保護されている。PHPのセキュリティチームと連携して対応した」というもので、状態は「観察中」でした。
一方で、サイトヘルスの版は 8.3.35 のままでした。版を変えずに修正だけを当てたのか、WAF(Webアプリケーションへの攻撃を手前で止める仕組み)などで攻撃の経路をふさいだのか、理由は書かれていません。22日 0:26 の時点でも、ステータスページは 23:00 の投稿のままでした。WordPress.org の告知は、ホスティング事業者がPHPの更新やWAFのルールで対応している可能性に触れていますが、この提供元が実際に何をしたのかは公表されていません。
3サイトは PHP-FPM で動いていました。GHSA-w8hw-w9fx-j79w は、完全な攻撃が実証されたのは Apache の mod_php で、FPM については「狙われうるが、完全な攻撃はまだ示されていない」としています。一方 GHSA-6wmf-4rv5-p3rp は、セッションの処理を使う攻撃を mod_php と FPM の両方で確かめたと書いています。FPM で成り立つかは、アプリケーション側の処理しだいだとしています。FPM だから安全とは言えないため、私たちは「保護済み」の発表を記録したうえで、版が修正版になるまでは「未確認」として扱い続けました。
30分ほど、キャッシュのないページがすべて 500 になった
23:32 から、キャッシュを通らない応答がすべて 500 エラーになりました。3サイトだけでなく提供元の公式サイトやブログも同じ状態で、別のネットワークから見ても 500 だったため、私たちの回線の問題ではないと判断しました。キャッシュが残っていたトップページなどは 200 で表示され、キャッシュのない詳細ページは 500 でした。
1分ごとに見張り、23:37:53 に復旧を確かめました。23:06 の確認では正常だったため、障害が続いたのは長くても30分ほどです。ステータスページには、この 500 エラーについての記載は出ていません。PHPの更新作業によるものかどうかは分からず、推測の域を出ません。
ここで分かったのは、キャッシュの効いたページだけを見ていると、PHPが止まっていても正常に見えることです。確認ツールでキャッシュを避けていたので、この障害も、復旧後に差がないことも、PHPを通った応答で確かめられました。
0時26分ごろ、8.3.36 を確かめた
23:39 の確認でも 8.3.35 のままでしたが、22日 0:26 ごろには、3サイトともサイトヘルスのPHPが 8.3.36(fpm-fcgi)になっていました。1回の表示で決めず、各サイトで、画面の表示を1回、サイトヘルスを取り直して5回、計6回読み、すべて同じ版でした。更新されたのは 23:39 から 0:26 までのどこかですが、正確な時刻は分かりません。
8.3.36 が今回の修正を含む版かどうかは、php.net の変更履歴(ChangeLog)で照合しました。8.3.36 の項目は「Fixed GHSA-w8hw-w9fx-j79w, GHSA-6wmf-4rv5-p3rp (Avoid state corruption via bailout).」の1行で、8.3 系にこれより新しい版はありません。アドバイザリ2件も、8.3 系の修正版を 8.3.36 としています。
あわせて 0:25 ごろに確認ツールを実行し、24ページとも、状態コード・エラー文言・タイトル・サイズ・応答時間が更新前の記録と変わらないことを確かめました。
CMSのクラウド版では、提供元の「緊急停止」方針に任せた
もう1つの案件は、CMSのクラウド版(提供元がサーバーごと運用する形)で構築中のサイトです。10月21日の日中、提供元から私たちあてに案内が届きました。要旨は次のとおりです。
- 製品の標準機能では、指摘されているPHPのセッション機能を直接使う処理は、今のところ見つかっていない。ただし、影響がないと確定したわけではない
- 詳細の公開前に、Session Upload Progress(ファイルのアップロードの進み具合をセッションに記録するPHPの機能)を無効にすることはしない
- 詳細の公開(21日 23:00)の前後を問わず、必要と判断すれば、利用者に事前に確認せずにサイトやサーバーを緊急停止する
- 停止されると困る場合は、当日 20:00 までに連絡してほしい
Session Upload Progress は、GHSA-6wmf-4rv5-p3rp で攻撃の経路の1つとして挙げられた機能です。公式の告知は、更新できない場合の緩和策として session.upload_progress.enabled=0 を挙げています(詳しくは解説記事を参照)。
止められる対象になりうるのは、公開前の検証環境と、翌日に構築する予定だった本番環境だけでした。クライアントが公開しているサイトは別のサーバーで動いていて、止められても公開中のサイトには響きません。そこで、事前の停止も、停止の見送りも申し出ず、提供元の判断に任せることにしました。
クライアントには、案内の要点とこの方針を共有しました。別の希望があれば 19:00 までに知らせてほしいと伝え、提供元の締め切りの 20:00 までに1時間の余裕を残しました。
振り返り:自分たちで確かめられたこと、待つしかなかったこと
版の数字だけで判断できない場面がある
今回は、版の数字と安全さが2つの向きでずれる場面がありました。ホスティングの提供元は、版が 8.3.35 のうちから「保護済み」と発表しました。逆に、Linuxのディストリビューションのパッケージでは、修正を取り込んでも版の数字が変わらないことがあります(PHPの脆弱性の解説記事で、手元のパッケージを確かめています)。
版の数字で「修正済み」と言えるのは、表示された版が、php.net の変更履歴やアドバイザリで修正版とされている版に達したときです。それより前の「保護済み」は、提供元の説明を受け入れるほかなく、私たちには中身を確かめる手段がありませんでした。そのため、発表は記録しつつ、判断は版で行いました。WordPress本体の版の確かめ方は、WordPress 7.1.2の修正は届いたかで扱っています。
提供元を待つ間に、自分たちでできたこと
PHPを直せない立場でも、提供元の対応を待つ間に私たちが実際にやれたことは次のとおりです。
- 末尾の番号まで版が見える場所を、修正版の公開前に見つけておく(今回はサイトヘルス)
- 更新前のページの動きを、キャッシュを避けて記録しておく
- 修正版の番号を、公式の変更履歴とアドバイザリの両方で確かめる
- 提供元のステータスページの投稿と、自分たちの確認の結果を、時刻つきで残す
- 自分たちが直接管理している環境(開発機など)は、提供元を待たずに止める
この記事の時刻つきの表も、4で残した記録から作っています。
連絡の締め切りは、手前にもう1つ置く
CMSの提供元が示した締め切りは 20:00 でした。クライアントの意向を聞いてから提供元に伝えるには、間に入る私たちの分の時間がいります。そこで、クライアントへの締め切りを1時間早い 19:00 に置き、返事がなければ「提供元に任せる」方針のまま進める形にしました。クライアントに求める返事も、「別の希望があるかどうか」の1点にしています。
同じ21日には、Node.js も 22.23.4・24.22.1・26.12.1 のセキュリティリリースを出しました(最も重いものは High)。こちらは私たちが自分で版を管理している側の話で、社内の端末とビルドの一括更新は第3回で記録します。
PHPを自分で管理していないサイトでも、版が末尾まで見える場所と、更新前のページの記録だけは、次の緊急修正の前に用意しておけます。
確認した範囲
2026年10月21〜22日の対応の記録(サイトヘルスの表示、確認ツールの記録、提供元のステータスページの投稿、CMSの提供元からの案内)をもとに書きました(自社の実務経験)。あわせて2026年10月22日に、php.net の告知(10月20日の予告と21日のセキュリティ告知)と変更履歴、GitHub の php/php-src のアドバイザリ2件、WordPress.org の告知、Node.js の告知を開いて確認しました(資料調査)。ホスティングの提供元が 8.3.35 のまま「保護済み」とした理由、23:32 ごろの 500 エラーの原因、PHPが 8.3.36 に変わった正確な時刻、3サイトへの攻撃の試みがあったかどうかは確認していません。CMSのクラウド版で、提供元がその後実際にサーバーを止めたかどうかは、この記事では扱っていません。脆弱性の再現は行っていません。
PHPで動くサイトの更新や保守の体制の見直しは、開発・AI・自動化のご相談からお問い合わせください。
参考資料
- Security advisory: Critical remote code execution vulnerabilities, update now(php.net、2026-10-21)
- Upcoming Critical PHP Security Release(php.net、2026-10-20)
- PHP 8 ChangeLog — Version 8.3.36(php.net)
- GHSA-w8hw-w9fx-j79w: RCE via OOM corruption(php/php-src)
- GHSA-6wmf-4rv5-p3rp: RCE via stale global state(php/php-src)
- Critical PHP Security Release(WordPress News)
- Wednesday, October 21, 2026 Security Releases(Node.js)









