PHP2Shellは、Wiz Researchが2026年10月21日に公表したPHP本体の脆弱性2件、CVE-2026-109618とCVE-2026-109619の総称です。どちらもCVSS v4.0で9.2と評価され、認証なしのリモートコード実行につながります。修正版はPHP 8.5.12・8.4.27・8.3.36・8.2.35で、PHP開発チームが明言しているのは、「更新だけが完全な対策」という方針です。本記事では、公式アドバイザリをもとに影響を受ける版と実行方式、自社サーバーの版と設定をコマンドで確かめる手順、すぐ更新できない場合の暫定設定、侵害の痕跡の見方までを2026年10月22日時点の情報で整理します。
まとめ:PHP2Shellは修正版8.5.12等への更新が唯一の完全な対策
やることは、Webリクエストを処理しているPHPを修正版へ上げることです。8.5系は8.5.12、8.4系は8.4.27、8.3系は8.3.36、8.2系は8.2.35が下限になります。アプリケーションのコードやプラグインを直しても塞がりません。欠陥はPHPのエンジン側にあり、WordPressやDrupalのコードが安全でも影響を受けます。
優先順位はApacheのmod_phpで外部公開しているサーバーが先頭です。公式は、mod_phpではアプリのコードが動く前に未認証のリクエスト1本で攻撃が成立する実証があるとしています。PHP 8.1以前は本家の修正版が出ないため、ディストリビューションのバックポートを確認するか、サポート中の版へ移ります。更新までの間は、session.upload_progress.enabled=0などの暫定設定とWAFで露出を減らせますが、どれも穴を完全には塞ぎません。
PHP2Shellの正体:PHP本体のメモリ安全性欠陥2件とCVSS 9.2の中身
2件とも、リクエストの処理中に致命的なエラー、とくにメモリ不足(OOM)で処理が打ち切られたときの後始末に関する欠陥です。PHPは1つのワーカープロセスで多数のリクエストを順に処理します。打ち切りで後始末が抜けると、壊れた内部状態や解放済みのメモリへの参照が残り、同じワーカーの次のリクエストがそれを使ってしまいます。
CVE-2026-109618:OOM時の中断で未初期化データが残る欠陥
公式のアドバイザリGHSA-w8hw-w9fx-j79wの題名は「RCE via OOM corruption」です。PHPはOOMのときlongjmp()で処理を抜けますが、リクエスト用のメモリが初期化しきれていない瞬間に抜けると、終了処理がその不完全なデータを有効なものとして扱います。
攻撃者がOOMを起こす手段は、multipart形式のPOSTです。Content-Lengthを持たないリクエストはpost_max_sizeの入口チェックを通り抜けます。1つのパートに付けられるヘッダの数にも上限がありません。空のファイル欄はmax_file_uploadsに数えられないのに、内部ではファイル情報の配列を作ります。これらを組み合わせると、見かけ上は上限内のリクエストでmemory_limitを使い切れます。
CVSSのベクトルはAV:N/AC:H/AT:P/PR:N/UI:Nで、ネットワーク越しに認証もユーザー操作も要りません。攻撃の複雑さは「高」でも、点数は9.2に達しています。
CVE-2026-109619:解放済みの状態を次のリクエストが読む欠陥
もう1件のGHSA-6wmf-4rv5-p3rpは「RCE via stale global state」です。エラー情報やセッションの状態はワーカーのグローバル領域に置かれ、本来はリクエストの終わりにリセットされます。致命的エラーでリセットが飛ばされると、解放済みメモリを指したまま次のリクエストへ持ち越されます(use-after-free)。
次のリクエストで通常の初期化より前に動く処理が、その古い状態を読みます。公式が確認済みとする読み手は2つです。1つは初期化前に適用されるINI設定が出す警告で、Apacheの.htaccessやphp_value、nginxなどからPHP-FPMへ送るPHP_VALUEが該当します。もう1つはセッションのアップロード進捗機能で、既定で有効、しかもアプリがsession_start()を呼んでいなくても動きます。
PHP 8.5のfatal_error_backtracesが有効な環境では、致命的エラーのバックトレースが毎回リセットされずに残ります。公式はこれを最も強い実証例とし、mod_phpでの攻撃成立の根拠に挙げています。
Wizの命名と発見経緯:AIで悪用コードを作れた点が新しい理由
PHP2Shellという名前は、発見者のWiz Researchのブログが付けたものです。PHPの公式文書はCVE番号で呼び、この名前を使っていません。Wizは2026年8月19日に最初の脆弱性を見つけ、8月24日にPHPへ報告し、10月21日に修正版と同時に公表しました。
Wizによると、欠陥は10年以上前からあり、PHP 5.4以降のほぼすべての版が少なくとも1件の影響を受けます。WordPress・Drupal・Joomlaの公式コンテナイメージ(latest)に対して未認証のリモートコード実行を実証し、別途、他のリクエストのパスワードやAPIキーを含むプロセスメモリを読み出せることも示しました。悪用コードの組み立てに生成AIのモデルを使い、対象ごとのメモリ配置への調整を数時間で済ませたと説明しています。
ここで確認しておきたい注意点は、次の1つです。Wizのブログの表は、どの不具合をどちらのCVEに入れるかの対応がPHP公式の題名と食い違います。本記事は修正の主体であるPHP公式のアドバイザリに合わせて書いています。対処は2件とも同じ修正版で済むため、番号の対応で迷う必要はありません。
影響を受けるPHPの版と実行方式:mod_phpが最も危ない理由と条件
php.netのセキュリティアドバイザリは、Webリクエストを処理するすべてのPHPを対象としています。PHP-FPM、Apacheのmod_php、php-cgi、FrankenPHP、LiteSpeedが名指しされています。差が出るのは、どの実行方式(SAPI)で動かしているかです。
修正版の一覧:8.5.12・8.4.27・8.3.36・8.2.35と8.1以前の扱い
| 系列 | 修正版(下限) | セキュリティサポート期限 | 本家の扱い |
|---|---|---|---|
| 8.5 | 8.5.12 | 2029年12月31日 | 修正版あり |
| 8.4 | 8.4.27 | 2028年12月31日 | 修正版あり |
| 8.3 | 8.3.36 | 2027年12月31日 | 修正版あり |
| 8.2 | 8.2.35 | 2026年12月31日 | 修正版あり・残り2か月 |
| 8.1・8.0・7.4 | なし | 終了済み | ソースのバックポートのみ |
期限はphp.netのサポート版一覧の値です。8.1以前について、PHPのセキュリティチームは例外的に最小限のソースバックポートを7.4・8.0・8.1向けのGitHubブランチで出しました。自前でビルドする人向けのもので、パッケージとしての修正版ではありません。開発中の8.6.0もRC4に修正が入っています。
SAPI別の危険度:mod_phpとPHP-FPM・FrankenPHPの成立条件
| 実行方式 | CVE-2026-109618 | CVE-2026-109619 |
|---|---|---|
| Apache+mod_php | アプリ実行前に成立(実証済み) | 実証済み(バックトレース・セッション経路) |
| PHP-FPM | 成立しうる(完全な攻撃は未実証) | セッション経路で実証済み |
| FrankenPHP | 影響を受ける可能性が高い | 既定構成での経路は未確認 |
| LiteSpeed(LSAPI) | アプリ次第で成立しうる | 条件付きの候補 |
mod_phpが危ないのは、リクエストの起動に失敗しても終了処理を必ず呼ぶ作りだからです。multipartの解析は起動時に行われるため、そこでOOMを起こせばアプリのコードが1行も動かないうちに壊れた状態が処理されます。PHP-FPMは起動に失敗した子プロセスを捨てるので、この経路は通りません。ただし、正常に起動した後のOOMや、セッション経路の欠陥は残ります。
FrankenPHPのワーカーモードは1プロセスでリクエストを処理し続ける方式で、仕組みはFrankenPHPとPHP-FPMの違いとワーカーモードの解説にまとめています。FPMなら安全という結論にはなりません。
アプリのコードが安全でも影響を受ける理由とWordPress等での実証
欠陥はmultipartの解析、セッション、エラー処理というPHPの土台にあります。Wizは、中身が「Hello World」だけのアプリでも影響を受けうると書いています。WordPressのプラグイン更新やWordPressのセキュリティ対策は別の攻撃に対する備えで、今回の穴は塞げません。
WizはOPcacheの共有メモリで型の取り違えを起こす不具合も報告し、WordPressでの攻撃に使いました。OPcacheを切って逃げる案は性能面で現実的でなく、結局は更新に戻ります。
自社サーバーの確認手順:PHPの版・SAPI・該当設定をコマンドで調べる
確かめるのは、Webリクエストを処理しているPHPの版、実行方式、暫定設定に関わるINIの値の3点です。コマンドラインのPHPとWeb側のPHPは別物の場合があるため、Web側を直接見ます。
php -vだけでは足りない:Web側SAPIの版と読み込むphp.iniの確認
Debian・Ubuntu系でPHP 8.3のFPMを使っている例です。RHEL系ではphp-fpmやhttpd -Mに読み替えてください。
# CLIの版(Web側と同じとは限らない)
php -v
# FPMの版と、FPMが読む設定値(プール単位の上書きは反映されない)
php-fpm8.3 -v
php-fpm8.3 -i | grep -E 'session.upload_progress.enabled|fatal_error_backtraces|memory_limit|post_max_size'
# Apacheにmod_phpが読み込まれているか(php_module が出たらmod_php)
apache2ctl -M 2>/dev/null | grep -i php
# プールやVirtualHost、nginxでの上書き(php_value・PHP_VALUE)を洗い出す
grep -rnE 'php_(admin_)?(value|flag)|PHP_(ADMIN_)?VALUE' /etc/php /etc/apache2 /etc/nginx 2>/dev/null
最後のgrepで.htaccessやPHP_VALUEが見つかったら、CVE-2026-109619の読み手になりうる設定です。値が非推奨や不正で警告を出していないかを確認します。PHP 8.5の非推奨設定はPHP 8.5の変更点と非推奨のまとめ、8.4はPHP 8.4の新機能と変更点で一覧できます。
ディストリ版PHPの見分け方:表示の版番号が古くても修正済みの場合
公式アドバイザリによると、Linuxディストリビューションと長期サポートの提供元には事前にパッチが渡されています。ディストリ版のPHPは上流の版番号を据え置いたまま修正だけを取り込む場合があり、php -vが8.3.36未満を示しても修正済みのパッケージかもしれません。
判断はパッケージの更新履歴で行います。Debian・Ubuntuならapt changelog php8.3-fpm、RHEL系ならrpm -q --changelog php-fpmにCVE-2026-109618と109619の記載があるかを見ます。記載が無ければ、対応上は未修正として扱う判断です。逆にPHPを自前でビルドしている環境は、上流の版番号がそのまま判断材料になります。
共用レンタルサーバーやPaaSの場合:事業者の更新告知で確認する点
共用サーバーでは利用者がPHP本体を入れ替えられません。事業者の告知で、利用中の系列が修正版へ更新済みか、旧系列(8.1以前)を選んでいる場合の扱いを確認します。管理画面で古い系列を選んだままのサイトは、事業者がバックポートを当てていない限り穴が残ります。
コンテナで動かしている場合は、ベースイメージのタグを固定していると更新が届きません。php:8.3-fpmのような可変タグでもイメージの再取得と再ビルドが要ります。IPAの事前告知は、ネットワーク機器などの製品内部でPHPが動いている場合にも開発元の情報を確認するよう呼びかけています。
すぐ更新できない場合の暫定設定:php.iniとFPMプールで塞ぐ攻撃経路
公式アドバイザリは、以下の設定を「特定の攻撃経路の露出を減らすが、安全にはしない」と位置づけています。検証環境での確認に時間がかかる場合のつなぎであり、更新の予定日を決めたうえで入れます。
109619向けの設定:upload_progressとバックトレースを止める
セッションのアップロード進捗を切り、PHP 8.5ではバックトレースの保持も切ります。アプリから上書きできないphp_admin_*で書き、全ワーカーを再起動します。ini_set()やFPMの.user.iniは適用が遅く効きません。
; /etc/php/8.3/fpm/pool.d/www.conf(FPMプール)
php_admin_flag[session.upload_progress.enabled] = off
; PHP 8.5のみ
php_admin_flag[fatal_error_backtraces] = off
; アップロード不要なら8M、必要なら32M
php_admin_value[post_max_size] = 8M
php_admin_value[upload_max_filesize] = 2M
# Apache+mod_phpはVirtualHost等に記述
php_admin_flag session.upload_progress.enabled off
# 反映は再起動で(全ワーカーを入れ替える)
sudo systemctl restart php8.3-fpm
アップロード進捗の機能はPHPマニュアルのセッションのアップロード進捗にある通り、アップロードの進み具合を表示する用途に限られます。使っているアプリはまれです。公式は修正版を入れた後も無効のままにする案を挙げています。
109618向けの設定:memory_limit=-1の副作用と上限の置き方
CVE-2026-109618の主な暫定策はmemory_limit=-1で、PHP側のメモリ上限を外して攻撃者が狙ったタイミングでOOMを起こせないようにします。上限を外すため、1リクエストがメモリを食い尽くすサービス妨害の危険が上がる点には注意が必要です。公式はその受け皿として、コンテナやcgroupのメモリ上限を推奨しています。
注意点は2つあります。cgroupをコンテナ全体にかけると、上限到達でマスタープロセスごと落ちることがあるため、ワーカー単位で止まる構成が望ましいとされています。またRLIMIT_ASやRLIMIT_DATAでの制限は、脆弱な経路そのものを誘発するので使いません。設定の書き方はPHP-FPMの設定マニュアルのphp_admin_valueの項を参照してください。
WAFは時間稼ぎ:Cloudflareの既定ルールと回避の試みの観測
Cloudflareのブログによると、同社は公表に先立つ10月21日3時02分(UTC)からFreeを含む全プランで防御ルールを既定で有効にしました。あわせて、顧客を狙った攻撃トラフィックと、ペイロードを変えてWAFを避けようとする動きを観測したと書いています。
回避が試みられている以上、WAFは更新までの時間稼ぎです。フロントのWAFやリバースプロキシでは、multipartのパート数・ヘッダ数・入力のネスト深さに上限を設けると、OOMを起こす手口の多くを入口で落とせます。仕組みはWAFの仕組みと選び方を参照してください。
更新の優先順位と判断基準:mod_php環境と8.1以前を先に片付ける理由
台数が多い組織ほど、全台を同時に上げられません。並べる順番の基準は、未認証で外から届くか、修正版がすぐ入るかの2点です。
最優先で止める環境:Apache+mod_phpで外部公開しているサーバー
Apache+mod_phpで外部に公開しているサーバーは、当日中に更新するか、間に合わなければ前段で止めます。アプリの認証やWAF以外の防御が働く前に攻撃が成立するためです。同じApacheでもApache HTTP Server 2.4の脆弱性の対応とは別の作業になります。Apacheを上げてもPHPは上がりません。社内向けの管理画面も、同じネットワークの端末が乗っ取られれば未認証で届くため後回しにしないでください。
8.1以前を使い続ける判断:バックポートで延命せず版上げに切り替える条件
8.1以前で動くシステムは、ディストリの長期サポートで修正版が出ているならまず当てます。出ていない場合、GitHubのバックポートを自前でビルドする道もありますが、本番の業務システムでは採りません。ビルドの検証と、今後の脆弱性への追従を自社で抱え続けることになるためです。
この場合は8.3以降への版上げを決め、それまでの数週間は暫定設定とWAFで受けます。8.2へ上げても12月31日でサポートが切れるため、移行先として選ぶのは8.3以降です。フレームワークの対応版の確認に時間がかかる場合でも、版上げの期日は先に決めてしまいます。
侵害の痕跡確認:500の連発・異常なPHPSESSID・ワーカー再起動の頻発
攻撃はアプリより下の層で起こるため、アプリのログにはほとんど残りません。Wizが挙げる手がかりは、multipartのリクエストに続くメモリ上限エラーや500応答の連発、異常に長いか壊れたPHPSESSIDのSet-Cookie、説明のつかないワーカーの入れ替わりです。PHP-FPMのログで子プロセスの異常終了が10月21日の前後に増えていないかを見ます。
痕跡が見つかった場合、更新に先立って必要なのは侵入後の状況確認です。代表的なのはWebシェルの設置で、探し方と除去の手順はWebシェルの検知・除去の手順にあります。メモリ読み出しでAPIキーやDBのパスワードが漏れた前提で、資格情報の入れ替えも計画に入れます。
自社で対応できる範囲と外部の脆弱性診断に依頼する範囲の線引き
PHPの更新と暫定設定は、サーバーを管理している担当者が自社で進められます。外に頼るべきなのは、痕跡が出た場合の調査と、台数や構成が多く棚卸しが追いつかない場合です。とくに、版上げで動かなくなるコードを洗い出す作業は、PHPのアップグレード経験がある開発会社に任せた方が早く終わります。
一創では、PHPで作られたWebシステムの脆弱性診断・セキュリティ診断で、版と設定の点検から改修までを受けています。修正版を入れた後の確認や、8.1以前からの版上げの見積もりにも対応しています。
PHP2Shellに関するよくある質問:WordPressや8.1以前の扱い
PHP2Shellの対応で、運用担当者から寄せられやすい質問に答えます。
WordPressのプラグインを更新すればPHP2Shellは防げますか?
防げません。欠陥はPHP本体にあり、WordPressのコアやプラグインの更新では直りません。必要なのはサーバーのPHPを8.5.12・8.4.27・8.3.36・8.2.35以降にすることです。管理画面の「サイトヘルス」に出るPHPの版番号は目安になりますが、ディストリ版のバックポートは番号に表れません。
PHP 7.4や8.0、8.1を使っている場合はどうすればよいですか?
PHP本家からは修正版が出ません。まずOSの提供元や長期サポートの契約先が修正パッケージを出しているかを確認し、あれば当てます。無ければ、暫定設定とWAFで露出を減らしながら、8.3以降への版上げを急ぎます。GitHubにはソースのバックポートがありますが、自前でビルドして保守し続ける負担が大きいため、業務システムでの長期運用には向きません。
PHP-FPMで動かしていればmod_phpより安全ですか?
危険度は下がりますが、安全ではありません。PHP-FPMは起動に失敗した子プロセスを捨てるため、mod_phpのようにアプリ実行前に成立する経路は通りません。一方、CVE-2026-109619のセッション経路はPHP-FPMでもリモートコード実行が確認されています。nginxからPHP_VALUEを送っている構成は、INI警告の経路も残ります。FPMでも修正版への更新が必要です。
PHP2Shellを悪用した攻撃はすでに起きていますか?
Cloudflareは顧客を狙った攻撃トラフィックと、WAFを避けようとする試みを観測したと公表しています。被害の件数や侵害の有無は示していません。PHP開発チームも事前告知の段階で、悪用の兆候が出れば公開を早めると書いていました。公表から日が浅く、攻撃コードが広まる前に更新を終える前提で動くべき段階です。
記事によってCVE番号と不具合の対応が違うのはなぜですか?
発見者のWizのブログと、PHP公式のアドバイザリで、不具合の分け方が異なるためです。PHP公式はCVE-2026-109618を「OOMでの破損」、CVE-2026-109619を「古いグローバル状態の再利用」としています。Wizの表は個別の不具合単位で2つのCVEに割り振っています。どちらも同じ修正版で直るため、対応作業には影響しません。番号の説明は修正の主体であるPHP公式に合わせるのが確実です。
関連記事
- FrankenPHPとは?PHP-FPMとの違い・ワーカーモードの仕組みと導入手順:実行方式ごとの危険度の差を、プロセスモデルから理解できます。
- PHP 8.5の変更点と新機能まとめ:8.5へ上げる際の非推奨と移行の注意点を確認できます。
- Webシェルとは?設置手口と検知・除去の手順:侵害が疑われるときの調べ方をコマンド例で解説しています。
- WAFとは?仕組みと企業の選び方:更新までの時間稼ぎとしてのWAFの位置づけを整理しています。
- WordPressセキュリティ対策:攻撃別の設定とWP-CLIでの確認手順:PHP本体以外の層の対策をまとめています。