PHP 8.3.6 は脆弱なのか ── バージョン番号だけで脆弱性対応を判断してはいけない
株式会社グルーヴサイン代表取締役の米沢です。
2026年10月21日、PHPに緊急の脆弱性が公表されました。認証なしでリモートからコードを実行されるたぐいのもので、CVSS v4.0 は 9.2。放置してよい種類の話ではありません。
弊社でも自社サーバとお客様の環境を点検しました。その過程で、バージョン番号だけを見て「危険だ」と判断すると間違えるという、毎回ひっかかる論点に改めてぶつかりましたので、点検の手順ごと書いておきます。
今回の脆弱性
公式(php.net)が公表した内容は次のとおりです。
| 項目 | 内容 |
|---|---|
| CVE | CVE-2026-109618(OOM処理の破損によるRCE)/ CVE-2026-109619(解放済みのリクエスト状態の再利用によるRCE) |
| 深刻度 | CVSS v4.0 9.2 |
| 影響 | 認証不要のリモートコード実行 |
| 修正版 | 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 |
いずれも、リクエストの処理中に中途半端な状態が残り、それが次のリクエストに持ち越されることで起きるものです。公式は mod_php 構成が最も危険(認証不要の実証コードが存在する)としており、更新以外に完全な解決策はない、と明記しています。
「うちは 8.3.6 だから古い」は、たいてい間違い
ここからが本題です。サーバでバージョンを確認すると、こう出ます。
$ php -v
PHP 8.3.6 (cli)
修正版は 8.3.36 です。8.3.6 は、それよりずっと前のバージョンに見えます。実際、この数字だけを見て「何年も放置されている」と判断してしまう例をよく見ます。
しかし、これは未修正という意味ではありません。
Ubuntu や RHEL などのディストリビューションは、上流の新しいバージョンに丸ごと上げる代わりに、セキュリティ修正だけを現在のバージョンに取り込むという方式を採っています。バックポートと呼ばれるやり方です。
なぜそうするのか。8.3.6 から 8.3.36 へ上げると、30回ぶんの変更が一度に入ります。その中には挙動の変わる修正も含まれ、動いていたシステムが止まるかもしれない。一方、脆弱性の修正だけを取り出して適用すれば、挙動は変えずに穴だけ塞げます。 長期サポート版の価値は、ここにあります。
その結果、上流のバージョン番号は上がりません。 代わりに、パッケージの側に別の番号が付きます。
php8.3-fpm 8.3.6-0ubuntu0.24.04.13
~~~~~~~~~~~~~~~~
ここが上がっていく
正しい確認方法は、CVE で引くこと
では何を見ればよいか。パッケージの変更履歴を、CVE番号で検索します。
zcat -f /usr/share/doc/php*-common/changelog.Debian.gz | grep -m5 "CVE-2026-109618"
実際に出てきたのがこれです。
php8.3 (8.3.6-0ubuntu0.24.04.13) noble-security; urgency=medium
* SECURITY UPDATE: Remote RCE via state corruption issue
- CVE-2026-109618
- CVE-2026-109619
修正は入っていました。バージョン番号は 8.3.6 のままですが、今回の2つのCVEは確かに塞がれていることが、これで確認できます。
RHEL 系なら rpm -q --changelog php | grep CVE-2026-109618、Debian 系なら上のコマンドです。「バージョン番号を比べる」のではなく「CVEが入っているかを引く」。 これが、バックポートされた環境での正しい確認手順です。
パッケージを当てて終わり、ではない
ここからが、見落とされがちな部分です。パッケージを更新しても、古いコードをメモリに抱えたまま動き続けているプロセスがあれば、そこは依然として脆弱です。
点検すべきは3か所あります。
① PHP-FPM が再起動されているか。 パッケージ更新時に自動で再起動されるのが普通ですが、確認は必要です。
systemctl show php8.3-fpm --property=ActiveEnterTimestamp
② Apache(mod_php)を使っていないか。 今回の勧告で最も危険とされた構成です。mod_php は Apache のプロセスに組み込まれるため、PHPを更新しても Apache を再起動しなければ有効になりません。
③ 常駐しているPHPプロセスがないか。 これが一番忘れられます。Laravel のキューワーカーのような常駐プロセスは、一度起動すると何時間も動き続けます。更新前に起動したワーカーは、更新後も古いコードで動き続けます。
3つまとめて機械的に確認するなら、削除済みのバイナリを掴んだままのプロセスを探すのが確実です。
for p in $(pgrep php); do
grep -l "php.*(deleted)" /proc/$p/maps 2>/dev/null && echo "要再起動: PID $p"
done
該当が出なければ、動いているPHPはすべて修正版です。弊社のサーバはここまで確認して、対応済みと判断しました。
自動更新が効いていても、残る穴がある
今回、自社サーバでは unattended-upgrades が動いており、公表の翌日の朝6時26分に自動で修正が適用され、その22秒後に PHP-FPM が再起動していました。人手を介さずに穴が塞がっていたわけです。
ただし点検の過程で、別の問題が見つかりました。カーネルの更新が、1年近く適用待ちのまま溜まっていたのです。
自動更新はパッケージを入れるところまではやりますが、カーネルや libc の更新は、再起動しなければ有効になりません。 そして unattended-upgrades の自動再起動は、既定で無効です。サービスを勝手に止めないための安全側の設定ですが、その結果、
- PHP は自動更新され、プロセスも入れ替わり、確かに安全になっている
- しかしカーネルは、何十回ぶんもの更新が「インストール済み・未適用」のまま積み上がっている
という、ちぐはぐな状態が生まれます。自動更新を入れていると「対応済み」のつもりになりやすい。自動化したものほど、定期的に目視で点検する必要があるという、ありふれた教訓でした。
このサーバは点検後に再起動し、溜まっていた更新はすべて適用済みです。あわせて、再起動が必要になったときだけ深夜に自動で再起動する設定も入れました。設定はこれだけです。
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
なお、この設定は 50unattended-upgrades に直接書かず、52- などの別ファイルに置くことをお勧めします。元のファイルはパッケージ更新で上書きされることがあるためです。
# 再起動が必要かどうか(Debian系)
[ -f /var/run/reboot-required ] && cat /var/run/reboot-required.pkgs
# 稼働中カーネルと、導入済みの最新を比べる
uname -r; ls -1 /boot/vmlinuz-* | sed 's|.*vmlinuz-||' | sort -V | tail -1
本当に危ないのは、サポートが切れた環境
ここまでは「更新できる環境」の話です。問題は、そうでない環境のほうです。
公式の勧告には、はっきりこう書かれています。PHP 8.1 以前は、プロジェクトからの更新提供が終了している。ベンダによるバックポートの有無を確認せよ。
つまり、
- PHP 8.2 以降 ── 上流から修正が出ている。ディストリビューションが対応していれば自動で塞がる
- PHP 8.1 以前 ── 上流の修正はない。OSベンダが有償の延長サポートを提供していれば塞がるが、そうでなければ穴が開いたまま
- PHP 5系・7系 ── ほぼすべての環境で、修正は提供されない
弊社がお預かりしているシステムにも、PHP 5系のまま動いているものがあります。こうした環境では「更新すれば終わり」が通用しません。現実的には、次のような積み重ねになります。
- 公式が示した暫定回避策を適用する(
session.upload_progress.enabled=0など。ただし完全な対策ではない) - 攻撃経路を潰す ── 外部からのアップロードを止める、WAFで弾く、管理画面をIP制限する
- mod_php であれば FPM へ寄せる(今回のように、構成の違いが危険度の違いになる)
- そもそもバージョンを上げる計画を立てる
最後の選択肢がいちばん健全ですが、動いているシステムのPHPを上げるのは、それ自体が一つのプロジェクトです。「上げられないから放置」ではなく、「上げるまでの間どう守るか」を決めておくことが、現実的な落としどころだと思っています。
点検のチェックリスト
今回やったことを、そのまま手順として残しておきます。
- バージョンではなくCVEで確認する ──
changelogを CVE番号で引く - PHP-FPM の再起動時刻を、更新時刻と突き合わせる
- mod_php を使っていないかを確認する(使っていれば Apache の再起動が必要)
- 常駐ワーカーが古いコードを掴んでいないか、
(deleted)で確認する - 再起動保留が溜まっていないか確認する(カーネル・libc)
- 自動更新そのものが動いているかを確認する(入れたつもりで止まっている例は多い)
- サポート切れのバージョンを洗い出し、回避策と移行計画を決める
同じ確認でお困りでしたら
自社の環境がどうなっているか分からない、古いPHPのまま動いていて手が出せない、そもそも誰に聞けばいいか分からない。そうしたご相談を、これまで何度も受けてきました。
バージョン番号を見ただけでは、安全かどうかは判断できません。 かといって、動いているシステムを不用意に上げれば止まります。その間をどう設計するかが、保守という仕事の中身です。
状況をお聞かせいただければ、まず何を確認すべきかの整理からお手伝いします。
レガシーPHPシステムの保守・引き継ぎのご相談を受け付けています。
初回のご相談・ヒアリングは無料です。