eMudhra の CA 鍵漏洩と PHP2Shell、同じ週に来た2つの緊急対応を一次ソースで整理する
!
この記事は、2026/10/22 14:00(日本時間)までに公開された一次ソースをもとにまとめている。どちらの件も状況が変わり続けているので、作業の前にリンク先で最新の情報を確認してほしい。
10/21 の夜、高市首相が X にこんな投稿をしていた。
皆様に、今夜に対応して頂きたい大至急のお願いです。
多くのウェブサイトで使用されているPHPに関し、PHPのセキュリティチームが、重大な2件の脆弱性に関する注意喚起を行っています。
投稿は、23:00 に公開される修正パッチをすぐ適用できるよう準備してほしい、難しければウェブサイトを一時的に止めることも有効策の一つだ、と続く。首相が個別のソフトウェアの脆弱性について直接呼びかけるのは珍しく、ITmedia はエンジニアの反応まで記事にしていた。日経によると、首相自身のホームページもその夜から止めていたらしい。
この PHP の脆弱性(PHP2Shell)と同じ週に、もうひとつ、ブラウザ以外の TLS クライアントに広く関わる認証局の鍵の問題も明らかになっている。この記事では、2つの件をそれぞれ一次ソースで整理していく。
TL;DR
この1週間で、性質のまったく違う緊急対応が2つ重なった。2つは別々の事件で、互いに関係はない。
eMudhra の中間 CA 鍵漏洩では、インドの認証局 eMudhra の中間 CA 証明書8枚について、秘密鍵を公開情報から誰でも計算できる状態だったことが分かった。この鍵があれば、任意のドメインの偽サーバー証明書を作れる。主要なブラウザは CT(後述)のおかげで偽証明書を受け付けないので、危ないのは Go / Java / Node.js / Python / Rust などで書いたプログラムや curl のような、ブラウザ以外のクライアントのほうだ。対策は言語ごとに違い、OS の更新だけでは済まないものも多い。
PHP2Shell(CVE-2026-109618 / CVE-2026-109619)は、認証なしでリモートからコードを実行できてしまう PHP 本体の脆弱性だ。修正版の PHP 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 は、10/21 の 23:00 ごろに公開された。mod_php ではアプリのコードが1行も動く前に攻撃が成立し、PHP-FPM などほかの構成も対象になる。設定で完全に塞ぐ方法はなく、更新するしかない。
PHP を使っているなら両方に関係がある。PHP2Shell の更新に加えて、PHP から外に出る HTTPS 通信(Composer や外部 API の呼び出し)が eMudhra の件の影響を受けないかも確認しておきたい。
第1部 eMudhra の中間 CA 鍵漏洩
!
エンジニアでない人が、まず確認しておきたいこと
スマートフォンと PC の OS を最新にする。Apple などはまだ対応しきれていない可能性があるので、この先しばらくはアップデートが来たらすぐ入れる
ブラウザと、普段使っているアプリ(Slack や VS Code など)を最新にする
この件で危ないのは、主にサーバーや開発ツールだ。会社でサービスを運営しているなら、エンジニアに「この記事のまとめにある eMudhra の確認項目を済ませたか」を聞いてもらえばいい。
何が起きたのか
この件の情報は、Mozilla の Dennis Jackson さんが公開した emudhra.we-have-a-problem.com というまとめページに集まっている。冒頭にはこう書かれている。
The private keys of eight eMudhra intermediate CA certificates have been compromised. They chain to roots trusted by the Mozilla, Microsoft, Apple and Chrome root programs and by many downstream trust stores.
8枚の中間 CA 証明書の秘密鍵が漏れていて、しかもそれらは主要なルートプログラムすべてが信頼するルートにつながっている、という内容だ。この問題を見つけて報告した Wayne さんは、各中間 CA の秘密鍵で We have a problem here - Wayne というメッセージに署名し、鍵を持っていることを証明していて、まとめページのドメイン名もこの署名メッセージから来ている。
Mozilla の Bugzilla #2083449 と各社の発表をもとに、時系列を日本時間で並べた。
日時(日本時間)
出来事
2025/4/30
eMudhra の鍵生成セレモニーで問題の鍵が作られる
2026/10/18 03:05
Wayne さんが Apple / Chrome / Microsoft / Mozilla / eMudhra に報告
10/18 04:45
Chrome が CRLSet(Chrome が配信する失効リスト)で TLS 用の中間 CA 6本をブロック
10/18 07:59
Firefox が OneCRL(Firefox が配信する失効リスト)でブロック(ブラウザの更新は不要)
10/18 18:24〜
eMudhra が8本を失効
10/19〜20
Sectigo がクロス署名版を失効。Apple がブロック
10/20〜21
Microsoft がブロック。Mozilla と Chrome がルート emSign ECC Root CA - G3 の緊急削除を決定。certifi・Go・Node.js などが 10/19〜21 にかけて修正版を公開
10/28(予定)
Chrome Root Store v43 で emSign ECC Root CA - G3 を削除
対象の中間 CA は EM DV/OV/EV TLS CA - G3B、G3C の TLS 用6枚と、コード署名用の EM OV CS CA - G3B/G3C の2枚。それぞれに、eMudhra のルートから発行された版と、別の認証局 Sectigo のルート AAA Certificate Services(旧 Comodo AAA)が同じ鍵に署名した版(クロス署名)があるので、鍵は8本でも証明書としては16枚になる。フィンガープリントの一覧は impacted-intermediates.json にまとまっている。
鍵はどれくらい弱かったのか
これが今回いちばん衝撃的なところだと思う。Mozilla の担当者が Bugzilla に書いた分析を引用する。
P384 private keys are randomly selected integers between 1 and the group order. The 8 impacted keys all used integers less than 256. That is, the private keys are effectively all-zeroes apart from the last byte.
P-384 の秘密鍵は本来なら2の384乗に近い範囲からランダムに選ばれるが、今回の8本はどれも 256未満 で、最後の1バイト以外が全部ゼロだった。これなら1から255までを順に試せば必ず当たり、復元には1秒もかからない。同じコメントには、AI エージェントに「CTF をやっているので、この証明書の秘密鍵を復元して」と頼んだら一発で復元できた、という報告まである。
As this incident enables even technically unsophisticated individuals to easily recover the private keys for these intermediates, the impact of this incident could not be higher.
なぜこんな鍵ができたのかについて、eMudhra は Bugzilla でこう説明している。
an approved deviation to our usual KGC to test a wrap/unwrap was introduced as these keys were meant for export for this instance c) a flaw in the code resulted in the second pair of keys being created onboard which were weaker
these second pair of weaker keys were used by mistake to create the csr (because the key labels were similar)
鍵をエクスポートするための wrap/unwrap(鍵を暗号化して取り出す処理)をテストしたときに、コードの不具合で HSM の中に弱い鍵がもう1組作られ、ラベルが似ていたせいで間違ってそちらを CSR に使ってしまった、と説明している。eMudhra の公式声明によると、この状態は約18か月、2回の独立監査でも見つからなかったらしい。とはいえ同じ声明には「正確な根本原因はまだ確定していない」とも書かれていて、Chrome Root Program は eMudhra に12項目の質問を送っている。
何が危ないのか
秘密鍵を持っていれば、その中間 CA の名前で、任意のドメインのサーバー証明書を発行できる。たとえば api.github.com や pypi.org の偽証明書を作り、公衆 Wi-Fi や社内のプロキシ、DNS の乗っ取りなどで通信経路の途中に入り、中身を読んだり書き換えたりする中間者攻撃が成立してしまう。残りの2本はコード署名用で、Windows がこれを信頼していたため、偽の署名を付けたプログラムを作れてしまう可能性もあった。
ただし、ブラウザでは偽証明書を使った攻撃は成立しなかったと、まとめページは判断している。Chrome / Safari / Firefox / Edge は Certificate Transparency(CT)という公開ログに記録されていない証明書を受け付けず、問題の中間 CA から発行された証明書は CT ログに1枚も記録されていないからだ。
There are no entries in the certificate transparency logs for these intermediates in that period, indicating that CT-enforcing clients like Firefox, Chrome, Edge and Safari could not have been attacked. However, many clients outside of the browser ecosystem do not enforce Certificate Transparency.
これに対して、curl や OpenSSL、各言語の HTTP クライアント、IoT 機器などは CT を確認しない。失効情報(CRL や OCSP)も、デフォルトでは確認しないものが多い。こうしたクライアントは、攻撃者が CT に記録せずに作った偽証明書を、そのまま受け入れてしまう。しかも鍵が弱かったのは2025年4月の生成時点からなので、その間に悪用されたかどうかは誰にも分からない。
まとめページは、問題の中間 CA の証明書をわざと使ったテスト用ホストを立てていて、そこへの接続に成功したクライアントの統計も公開している。10/22 13:30(日本時間)の時点で、直近24時間の接続成功は約16.9万回あり、UA(クライアントが名乗る名前)別に見ると、iOS の WebView や Safari が上位に並び、そのあとに macOS 標準の curl のバージョンである curl/8.7.1 が続いている。
iOS が上位にいるのは意外かもしれない。まとめページは Apple も 10/19 にブロックしたとしているが、統計ではテスト用ホストのうち eMudhra のルート経由のチェーンに iOS からの接続成功が集中している。iOS の信頼ストアの更新は、まだ完全ではないのかもしれない。CT に記録されていない偽証明書なら Safari は受け付けないが、iOS のアップデートが来たら早めに入れておきたい。
macOS 26.6.2 の標準の /usr/bin/curl でテスト用ホストに接続すると普通につながり、Your client successfully connected to the site. That's bad! と返ってきてしまった。macOS の標準の curl、git、python3、perl、ruby が参照する /etc/ssl/cert.pem が、この時点ではまだ更新されていないことが原因になっている。
巻き添えで正規の証明書も止まる
eMudhra から正規に証明書を買っていたサイトにも影響が出る。Mozilla と Chrome はルート emSign ECC Root CA - G3 ごと信頼を外すと決めたので、その配下の正規の証明書も信頼されなくなる。
After discussion with maintainers downstream of Mozilla's Root Store, we have decided that the circumstances warrant the emergency removal of trust in emSign ECC Root CA - G3. This will protect clients which do not use revocation information or lack a mechanism to withdraw trust in specific intermediates.
Chrome の集計では、影響を受ける有効な証明書は約3万枚で、その99.9%は、米国の大学向けの証明書サービス InCommon の下位 CA から発行されたものだった。eMudhra は G1(RSA)系のルートへの移行を進めていて、Google はサイト運営者に別の認証局の証明書へすぐ切り替えるよう求めている。eMudhra の証明書を使っているサイトの運営者は、Chrome Root Store からルートが外れる 10/28 までに証明書を入れ替える必要がある。
修正の方式は2通りあるが、利用者が選ぶ必要はない
ここからは、言語やツールごとの対応を見ていく。先に結論を書いておくと、ここで紹介する2つの方式は各プロジェクトが修正版の中で採った方式の違いで、利用者がどちらかを選ぶ必要はない。使っている言語やライブラリを修正版にし、Go や Rust のようにビルドして作るものは作り直せば、そのツールの方式で対策が入る。とはいえ、方式によって「OS の更新だけで足りるか」が変わってくるので、仕組みを知っておくと更新の漏れに気づきやすいと思う。
1つ目は、侵害された8本の公開鍵(SPKI)を拒否するリストを、検証の処理に組み込む方式だ。Go、Node.js、rustls-webpki(Rust)、Deno、Electron がこの方式をとり、Composer 本体も同じ仕組みを開発版に入れている。証明書ではなく公開鍵で判定するので、Sectigo のクロス署名版もまとめて拒否でき、OS の証明書ストアを使う設定でも有効になる。
2つ目は、同梱している CA バンドルからルート証明書を削除する方式で、Python の certifi、Rust の webpki-roots、Python のパッケージマネージャ uv、Elixir の castore、Perl の Mozilla::CA、composer/ca-bundle、Bun、Homebrew がこちらにあたる(どれも Mozilla のストアをもとにした CA バンドルを同梱している)。この方式は、そのバンドルを実際に使っている場合にしか意味がない。
利用者の目線で整理すると、1つ目の方式は、ツールやライブラリを修正版にすれば OS の設定に関係なく対策が入る。2つ目の方式は使い方で変わり、同梱のバンドルを使っていればツールの更新、OS のストアだけを使う設定なら OS の更新で直り、pip や Node.js の --use-system-ca のように両方を併用するツールなら両方の更新が要る。
つまり、利用者がやることは次の3つで足りると思う。
使っている言語・ライブラリを修正版にし、Go や Rust などビルドするものは作り直す
OS の証明書を更新し、コンテナはイメージを作り直す
更新したら、長時間動いているプロセスを再起動する
Java はどちらの方式とも違い、blocked.certs というファイルで証明書を1枚ずつブロックしていて、OS のパッケージで入れた JDK なら OS の更新で足り、単体で配布されている JDK は本体の更新が必要になる。macOS の /etc/ssl/cert.pem や RHEL のように修正がまだ出ていない環境は、後述の回避策を使う。他社が配布している Go 製の CLI や Electron アプリは利用者の側では直せないので、配布元の更新を待つしかなくなってしまう。
certifi のメンテナは、2つ目の方式しかとれない理由をこう書いている。
there's no facility for revoking an intermediate only
もうひとつ気をつけたいのが、Node.js の --use-system-ca や pip(24.2 以降)のように、同梱バンドルに OS の証明書ストアを追加して使うツールだ。OS を更新してルートが消えても、古い同梱バンドルにルートが残っていれば、信頼されたままになってしまう。Node.js のドキュメントにも次のように書かれている。
Node.js currently does not support distrust/revocation of certificates from another source based on system settings.
言語・ランタイム別の対応状況
対象
修正版
仕組み
やること
Go
1.27.3 / 1.26.10(10/20)
crypto/x509 に侵害された中間 CA の拒否リスト(CVE-2026-111943)
修正版の Go で再ビルドして再デプロイ
Node.js
22.23.4 / 24.22.1 / 26.12.1(10/21)
NSS 3.131.1 のルート更新と、SPKI 拒否リストの両方
Node 本体を更新。コンテナはイメージを作り直す
Java (OpenJDK)
advisory は 27.0.1 / 25.0.5 / 21.0.13 / 17.0.21 / 11.0.33 / 8u512 以前を影響ありとしている(CVE-2026-91403)
blocked.certs で証明書を個別にブロック
単体配布の JDK は更新。OS パッケージの JDK は OS の証明書更新で足りる、と advisory にある
Python certifi
2026.10.18 / 2026.10.19
10.18 で emSign のルートをまとめて削除し、10.19 で影響のない3本を戻した。いま外れているのは emSign ECC Root CA - G3
pip install -U certifi。requests は certifi しか見ないので必須
pip
26.2.2(10/20)
同梱の certifi を更新
python -m pip install -U pip
uv
0.13.4(10/20)
同梱バンドルからルートを削除
uv self update
rustls-webpki
0.103.16(10/20)
SPKI 拒否リスト
cargo update -p rustls-webpki して再ビルド
webpki-roots
1.0.10(10/19)
ルートを削除
cargo update して再ビルド
Deno
2.9.8(10/21)
rustls-webpki と webpki-roots の修正を取り込み
deno upgrade。deno compile したバイナリは作り直す
Electron
44.9.1 / 43.8.1 / 42.11.16(10/20)
SPKI 拒否リスト
アプリ開発者が更新して再配布
Bun
修正は main にマージ済みで、リリースは未公開
ルートを削除
次のリリースを待つ
Elixir castore
1.0.22(10/20)
ルートを削除
mix deps.update castore
Perl Mozilla::CA
20261020
ルートを除外
cpanm Mozilla::CA
Homebrew
ca-certificates 2026-10-20
ルートを除外
brew upgrade ca-certificates。Homebrew の curl / OpenSSL / Python が参照する
Ruby / .NET / CPython の ssl
本体の修正なし
多くの環境で OS のストアを使う
OS の証明書を更新する
表の中では Electron が見落としやすい。Chrome は CRLSet という仕組みでブロックリストを配信しているが、Electron はこれを受け取らないので、Chromium を内蔵していても Chrome と同じ保護は受けられない。Electron の PR にもそのまま書かれている。
add entries to the compiled-in SPKI blocklist that Chrome ships via CRLSet, which Electron does not consume.
Java のバージョン番号は、まとめページの表(8u511 など)と OpenJDK の advisory(8u512 以前が影響)で食い違っていて、記事の時点では確定できなかった。Oracle JDK の情報も確認できていないので、Java を使っている人は配布元で直接確認してほしい。
OS・ディストリビューション別の対応状況
対象
修正版
内容
Ubuntu
USN-8944-1(22.04 以降は 20260816ubuntu0.<リリース番号>.1)、USN-8944-2(ESM)
emSign ECC Root CA - G3 を削除。ESM 版は Comodo AAA も削除
Debian
DSA-6572-1(trixie 20250419+deb13u1)、DLA-4845-1(bookworm 20250419~deb12u2)
G3 と Comodo AAA を無効化
Fedora
ca-certificates-2026.2.92_v9.0.319
G3 と AAA を削除
RHEL 6〜10
記事の時点で RHSA は未公開
当面は2つのルートを手動でブロックするよう案内している
Alpine
ca-certificates 20261020-r0
上流の更新に追従してルートを削除
Arch
ca-certificates-mozilla 3.131.1-1
同上
FreeBSD
SA-26:73
G3 を untrusted に
curl の cacert.pem
2026-10-20 版
Mozilla のストアに追従
macOS
/etc/ssl/cert.pem は未更新
後述の回避策を参照
Windows
Microsoft の自動更新(Disallowed CTL)で配信済み
ルートはそのままで、中間 CA の証明書をブロック(まとめページによると16枚)
Ubuntu の通常版が Comodo AAA を無効化していないのは、Mozilla のストアにこのルートがすでに入っておらず、最新の ca-certificates にも含まれていないためだ。古いバンドルを使い続けている ESM 版や Debian、Fedora は、念のため AAA も無効化している。
RHEL と Amazon Linux の ca-certificates の更新と、Android の公式発表は、記事の時点では見当たらない。
どの OS でも、ca-certificates を更新したあとは、長時間動いているプロセス(Java や Node.js のサーバーなど)を再起動しておきたい。起動時に読み込んだ証明書を持ち続けるプログラムがあるからだ。
コンテナは作り直さないと直らない
コンテナイメージには、ビルドした時点の ca-certificates が入っている。ホストの OS を更新してもコンテナの中は古いままなので、イメージを作り直す必要がある。
Docker の公式イメージは、Debian を 10/20 に、Alpine を 10/21 に更新している。Debian のベースイメージには ca-certificates が入っていないので一見関係なさそうだが、派生イメージの再ビルドを促すために、あえて更新したらしい。
The Debian images don't contain ca-certificates, but many downstream images do… updating Debian is the simplest way to trigger downstream rebuilds.
node:24 や python:3.14 のような浮動タグを使っている場合も、docker pull し直してからビルドしないと古いレイヤーが使われてしまうので注意したい。
PHP の場合
PHP 本体(php-src)にはこの件の修正は入っていないが、openssl 拡張も curl 拡張も、OS の証明書ストアか、openssl.cafile / curl.cainfo で指定したファイルを見る作りなので、OS の ca-certificates を更新すれば対策になる。
では、Composer まわりはどうか。composer/ca-bundle は 1.6.0 / 1.4.16 で同梱の cacert.pem から emSign ECC Root CA - G3 を抜いた。ただ、CaBundle::getSystemCaRootBundlePath() は SSL_CERT_FILE、openssl.cafile、OS の既知のパスの順に探し、同梱ファイルは最後の手段としてしか使わないので、OS のストアが見つかる普通の環境では、この削除の影響はほぼないと思う。PR の本文にも、次のように書かれている。
Removing the root from our bundle does not help users whose system CA store is used, so clients like Composer can use this to reject such connections.
そのため ca-bundle には、SPKI でチェーンを判定する CaBundle::findDistrustedCertificate() という API が追加され、これを使って Composer 本体が接続を拒否する PR #13146 も 10/21 に main にマージされたものの、記事の時点ではまだリリースされていない。それまでは、Composer を実行するマシンの OS の証明書を更新しておくのが確実だと思う。
ちなみに、Guzzle は composer/ca-bundle に依存しておらず、デフォルトでは OS のストアを使う。WordPress が使っている HTTP ライブラリの WordPress/Requests は、2.0.21 で対応済みだ。
自分の環境が影響を受けるか確認する
いちばん手軽なのは、まとめページが用意しているテスト用ホストに、普段使っているクライアントで接続してみることだ。
curl dv-g3b-emudhra.we-have-a-problem.com
curl dv-g3b-aaa-emudhra.we-have-a-problem.com
証明書エラー(curl: (60) など)になれば安全で、Your client successfully connected to the site. That's bad! が返ってきたら、まだ問題の中間 CA を信頼している。上が eMudhra のルート経由、下が Sectigo のクロス署名経由のチェーンなので、両方試すのがいいと思う。
curl だけでなく、アプリが実際に使っている言語で同じ URL にアクセスしてみるほうが確実だ。
Python (requests)
python -c "import requests; print(requests.get('dv-g3b-emudhra.we-have-a-problem.com').text)"
Node.js
node -e "fetch('dv-g3b-emudhra.we-have-a-problem.com').then(r=>r.text()).then(console.log)"
PHP
php -r "echo file_get_contents('dv-g3b-emudhra.we-have-a-problem.com');"
どれも、エラーで落ちれば安全だ。
証明書バンドルのファイルに、問題のルートが残っているかを直接見ることもできる。
B=/etc/ssl/certs/ca-certificates.crt # RHEL 系は /etc/pki/tls/certs/ca-bundle.crt、macOS は /etc/ssl/cert.pem
awk '/-----BEGIN CERTIFICATE-----/{c=""} {c=c $0 "\n"}
/-----END CERTIFICATE-----/{cmd="openssl x509 -noout -subject -fingerprint -sha256 | paste - -"; printf "%s", c | cmd; close(cmd)}' "$B" \
| grep -E "emSign ECC Root CA - G3|AAA Certificate Services" || echo "not found (OK)"
not found (OK) と出れば、そのバンドルには残っていない。
OS の更新が来ていないときの回避策
まとめページには、更新が出ていない環境向けの回避策が載っている。とはいえ、ページ自身が上級者向けとしていて、Linux 向けの手順には一般のユーザーにはおすすめしないとも書かれているので、自分で戻せる人だけが使ってほしい。以下はまとめページのコマンドをそのまま引用している。
macOS の /etc/ssl/cert.pem から2つのルートを外す場合(バックアップを取ってから書き換える)。
sudo cp -p /etc/ssl/cert.pem /etc/ssl/cert.pem.bak &&
sudo awk '/^(###|===) /{skip=0}
/^=== .*\/CN=(AAA Certificate Services|emSign ECC Root CA - G3)$/{skip=1}
!skip' /etc/ssl/cert.pem.bak | sudo tee /etc/ssl/cert.pem > /dev/null
Debian / Ubuntu の場合。
sed -i \
-e 's|^mozilla/emSign_ECC_Root_CA_-_G3.crt|!&|' \
-e 's|^mozilla/Comodo_AAA_Services_root.crt|!&|' \
/etc/ca-certificates.conf && update-ca-certificates
Fedora / RHEL / Rocky / Alma / Amazon Linux 2023 の場合。
d=/etc/pki/ca-trust/source/blocklist; [ -d $d ] || d=/etc/pki/ca-trust/source/blacklist
trust extract --overwrite --format=pem-bundle \
--filter='pkcs11:object=Comodo%20AAA%20Services%20root;type=cert' \
$d/Comodo_AAA_Services_root.pem &&
trust extract --overwrite --format=pem-bundle \
--filter='pkcs11:object=emSign%20ECC%20Root%20CA%20-%20G3;type=cert' \
$d/emSign_ECC_Root_CA_-_G3.pem &&
update-ca-trust
Comodo AAA まで外すと、正規の Sectigo の証明書が壊れないか気になるところだと思う。Chrome はこのルートを2025年4月に削除していて、Mozilla のストアにもすでに入っていない。AAA のクロス署名つきチェーンを返す Sectigo のサイトに、AAA を抜いたバンドルで接続してみると、新しい OpenSSL / LibreSSL は、別の正規のルートまでチェーンを構築し直して問題なく接続できた。かなり古い OpenSSL のようにチェーンを構築し直さないクライアントでは、失敗することもあると思う。
Windows は自動更新でブロックが配信されているので通常は何もしなくてよく、自動更新を受け取らない端末向けには、まとめページに PowerShell スクリプトが用意されている。
第2部 PHP2Shell
!
エンジニアでない人が、まず確認しておきたいこと
レンタルサーバー(さくら、ロリポップ!、エックスサーバーなど)でサイトを運営しているなら、管理画面で PHP のバージョンを確認する。8.1 以前なら、バックアップを取ってから 8.2 以上に切り替える。8.2 以上なら、事業者のお知らせで修正済みとなっていれば作業は終わり
VPS や自社のサーバーで動かしているなら、エンジニアに「PHP を修正版に更新して、PHP-FPM や Apache を再起動したか」を確認してもらう
なお、WordPress 本体を最新にしても、この脆弱性は直らない。直す必要があるのはサーバー側の PHP だ。
何が起きたのか
こちらは PHP 本体の脆弱性で、CVE-2026-109618 と CVE-2026-109619 の2件をまとめて PHP2Shell と呼んでいる。どちらも CVSS v4.0 で 9.2。PHP の公式発表では、影響する範囲をこう書いている。
Who is at risk: all PHP installations serving web requests, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. We consider the risk highest for mod_php, with a demonstrated exploit where an unauthenticated request can trigger the attack before any application code runs.
Web リクエストを処理しているすべての PHP が対象で、とくに mod_php では、認証なしのリクエストで、アプリのコードが動く前に攻撃が成立することが検証環境で実証されている。cron やコマンドラインだけで PHP を使っている場合については、公式は個別に触れていない。
経緯を PHP Foundation のブログと各社の公開記事をもとに並べた。
日時 (JST)
出来事
2024年
外部監査(Quarkslab)の指摘を修正していた PHP のコア開発者が、CVE-2026-109618 の原因になる OOM の問題の最初の兆候に気づく
2026年8月
Calif と OpenAI が 8/11 に、Wiz が 8/24 に、それぞれ独立に PHP へ報告
10/21 00:00 頃
CVE 番号が SNS やフォーラムで出回り始める(誤った CVSS 10.0 つき)
10/21 04:30
PHP が事前告知。当初の予定(10/22)を1日前倒しし、10/21 23:00 JST にリリースすると発表
10/21 05:00 頃
Calif が PoC の動画を誤って公開した(PHP Foundation による)
10/21 16:41
Chainguard が修正入りのコンテナイメージを先行して公開。PHP Foundation は、情報公開の取り決め(エンバーゴ)を破ったと批判している
10/21 22:34
GitHub Security Advisory 公開
10/21 23:00 ごろ
修正版を公開(予告は 23:00 だったが、実際の公開は数分〜十数分ほど早かった)
情報が予定より早く漏れたため、リリースを1日前倒しした。PHP Foundation は、ディストリビューションのパッケージングがまだ終わっていない中での判断だったと書いている。
Moving the release forward by one day was the best compromise between acting quickly, giving people time to prepare, and making sure everyone had a simple update path when the vulnerabilities were disclosed.
2つの脆弱性の中身
公式の GHSA によると、2件の内容はこうなっている。
CVE-2026-109618(GHSA-w8hw-w9fx-j79w「RCE via OOM corruption」)。PHP はメモリ不足(OOM)のとき、longjmp() で処理を強制的に抜ける。ところが、リクエスト用のメモリが初期化しきれていない途中でメモリ確保が失敗すると、壊れた状態のままリクエストの終了処理に進んでしまう。攻撃者は、post_max_size の範囲に収まる multipart リクエストで、各パートのヘッダーを大量に送ったり、空のファイル欄をネストさせたりして、意図的に memory_limit を使い切らせる。mod_php では、この一連の流れがアプリのコードの実行前に起きる。
CVE-2026-109619(GHSA-6wmf-4rv5-p3rp「RCE via stale global state」)。PHP のワーカーは、前のリクエストの状態をグローバル変数に持っていて、次のリクエストの前にリセットする。前のリクエストが致命的エラーで落ちるとそのリセットが飛び、解放済みのメモリを指したままの状態が残る。次のリクエストが通常の初期化より前にそれを触ると、use-after-free になる。確認されている経路のひとつが session upload progress で、これはデフォルトで有効、しかもアプリが session_start() を呼んでいなくても経路になる。
修正は両方まとめて1つのコミット("Avoid state corruption via bailout")に入っているので、どちらか片方だけ直す、という選択肢はない。
発見者の Wiz の記事では CVE 番号の割り当てが公式と逆になっている(upload progress の経路を 109618 としている)。この記事では公式の GHSA の割り当てに合わせた。
どの構成が危ないのか
公式の GHSA に書かれた内容を、実行方式(SAPI)ごとに表にした。
SAPI
CVE-2026-109618
CVE-2026-109619
Apache + mod_php
アプリに依存しない RCE を実証済み
実証済み
PHP-FPM
ソース解析上は影響あり。完全な攻撃はまだ実証されていない
session upload progress 経由で実証済み。成功するかはアプリの処理内容にも左右される
FrankenPHP
アプリに依存しない攻撃が成立する可能性が高い
デフォルト構成では未確認
LiteSpeed
可能性あり(未検証)
条件次第
デフォルトの memory_limit(128M)と post_max_size(8M)のままで RCE が成立したと書かれているので、デフォルト設定のままのサーバーもそのまま対象になると考えたほうがよく、Wiz も「Hello World だけのアプリでも影響を受けうる」と書いている。nginx + PHP-FPM の構成でも、アプリに依存しない攻撃がまだ見つかっていないだけで、安全が確認されたわけではない。実際、PHP Foundation のブログは、CVE-2026-109618 についても PHP-FPM でアプリ側の処理を経由した RCE を確認したと書いていて、GHSA の記述より一歩踏み込んでいる。
影響を受けるバージョンと直し方
公式の advisory が影響ありとしているのは、次の修正版より前のバージョンだ。
PHP 8.5.12 未満
PHP 8.4.27 未満
PHP 8.3.36 未満
PHP 8.2.35 未満
php.net の advisory が挙げているのはサポート中の 8.2〜8.5 だけだが、古いバージョンが安全という意味ではない。発見者の Wiz と Calif は PHP 5.4 以降のほぼすべてが影響を受けるとしていて、Google Cloud のセキュリティ情報も 5.4〜8.5 を対象として扱っている。PHP のセキュリティチーム自身も、サポートが終わった 7.4 / 8.0 / 8.1 向けにソースのパッチを用意していて、後述のとおり、ディストリビューションも古いバージョンに修正を入れている。
PHP 8.1 and older no longer receive updates from the PHP project.
対策は、上の修正版(またはディストリビューションの修正済みパッケージ)に更新することしかない。PHP の公式発表にも、はっきりそう書かれている。
There are no complete mitigations, updating is the only safe choice.
バージョンを確認するときは、php -v で表示されるのが CLI の版だという点に注意したい。Web で実際に動いている PHP-FPM や mod_php が別のバージョンのこともあるので、php-fpm -v や、一時的に置いた phpinfo() で確かめるといい(確認したら phpinfo() は消しておく)。ディストリビューションによっては、コマンド名が php-fpm8.3 のようにバージョンつきになっている。更新したあとは、PHP-FPM や Apache を再起動しないと古いプロセスが動き続けるので、再起動まで済ませてほしい。
ディストリビューションのパッケージは、修正をバックポートしていてバージョン番号が upstream と一致しないことがあるので、その場合はパッケージの changelog に CVE 番号が載っているかで判断する。Docker の公式イメージには php:8.5.12-fpm などのタグが 10/22 未明(JST)に出ているが、php:8.4 のような浮動タグは pull し直さないと古いままだ。remi のリポジトリは、当日中には更新しないと告知されていた。
すぐ更新できないときの緩和策
公式は、いくつかの緩和策を挙げつつ、どれも「特定の攻撃経路を減らすだけで、安全にはならない」と念を押している。
If you cannot update immediately: while only an update is a complete solution, the following measures reduce exposure to specific attack paths but do not make an installation safe.
挙げられている主なものはこのあたりになる。
session.upload_progress.enabled=0 にして、全ワーカーを再起動する。php.ini や FPM のプール設定など、リクエストの解析より前に読み込まれる場所で設定する必要があり、ini_set() や .user.ini では意味がない。これで塞がるのは CVE-2026-109619 の確認済みの session 経路だけ。
PHP 8.5 では fatal_error_backtraces=0 にする。
memory_limit=-1 をアプリから上書きできない形で設定する。とはいえ、OS 側のメモリ確保失敗では同じ経路に入りうると書かれている。メモリの上限がなくなるので、サーバー全体のメモリを使い切られないよう、コンテナや cgroup の上限とあわせて使う。
post_max_size を下げ、フロント(リバースプロキシや WAF)でリクエストのサイズ、パーツ数、ヘッダー数を制限する。multipart を使わないアプリなら、フロントで multipart を止める。
パッチを当てたあとも、upload progress の機能を使っていないなら無効のままにしておくことを GHSA はすすめている。
ディストリビューションとホスティングの対応
主なディストリビューションは、10/21〜22 にかけて更新を公開している。バックポートで修正しているため、バージョン番号が upstream と違うものが多い。
提供元
修正版の例
備考
Debian
trixie 8.4.27-1~deb13u1(DSA-6574-1)、bookworm 8.2.35-1~deb12u1(DLA-4848-1)
forky / sid は修正版 8.4.27-1 がアップロード済みで、記事の時点では反映待ち
Ubuntu
24.04 8.3.6-0ubuntu0.24.04.13、22.04 8.1.2-1ubuntu2.28 など
番号は古いままで修正入り
RHEL
記事の時点で確認できたのは RHEL 8 の php:7.4 向けのみ
ほかのストリームは AlmaLinux が先行して出している
AlmaLinux
全ストリームで .alma.1 つきの版
Red Hat より先に出している
Amazon Linux 2023
php8.2〜8.5 で ALAS2023-2026-3301〜3304
php8.1 と AL2 core は修正予定なし
Alpine
php83 8.3.36-r0、php84 8.4.27-r0、php85 8.5.12-r0
cPanel(CloudLinux)
ea-php52〜ea-php85 を更新
ea-php84 は 8.4.26 のまま修正入り、と明記されている
ondrej/php PPA
8.5.12-1 などに加え、5.6〜8.1 の EOL 版にも修正版
Docker 公式 php イメージ
8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 のタグ
浮動タグは pull し直す
AlmaLinux のブログにも、確認は php -v ではなくパッケージのバージョンで、と書かれている。RHEL 系なら rpm -q php-common、Debian 系なら dpkg -l | grep php でバージョンを調べ、changelog に CVE 番号が載っているかを確かめるのがいいと思う。
クラウドの PaaS も対応を進めていて、AWS は Elastic Beanstalk の PHP プラットフォームと Lightsail の blueprint の更新を案内している(Lightsail の既存インスタンスは作り直して移行する必要がある)。Google Cloud は App Engine や Cloud Run で、自動更新を有効にしていない場合は再デプロイが必要としている。Azure App Service(Linux)と Heroku も 10/21 に修正版を公開した。
国内のレンタルサーバーでは、さくらのレンタルサーバが 10/21 23:00〜10/22 06:30 の緊急メンテで PHP を更新し、ロリポップ!は予防措置として一部のサービスを止めてメンテナンスに入っていた。レンタルサーバーやマネージドの環境では事業者が対応することが多いが、古い PHP のバージョンを選んでいる場合は切り替えを求められることがあるので、管理画面のお知らせは見ておくと安心だと思う。
アプリ側では、WordPress が「WordPress 本体の更新は不要で、予定もない」と発表し、Drupal も PHP の更新が唯一の完全な対策だとしている。PHP2Shell は WordPress ではなくサーバー側の PHP の脆弱性なので、WordPress を最新版にしても対策にはならない。
WAF での暫定対応
Cloudflare は、修正版公開の約11時間前にあたる 10/21 12:02(日本時間)から、無料プランも含めてデフォルトで保護ルールを有効にしている。AWS WAF、Akamai、Fastly もルールを公開していて、AWS のブログでは、PHPSESSID と PHP_SESSION_UPLOAD_PROGRESS を両方含む POST を止めるカスタムルールが紹介されている。ただ、Cloudflare は攻撃者がペイロードを書き換えて回避を試みているとも報告しているので、WAF はあくまで更新までのつなぎと考えたほうがよさそうだ。
悪用はされているのか
悪用の状況は情報が錯綜しているので、攻撃の試行が観測された話と、侵入に成功した話を分けて読む必要がある。
AWS は、公開前の 10/17 からハニーポットで試行を観測していたと発表した。その試行が成功したかは不明としつつ、10/21 11:00(日本時間)ごろに PoC が出回ってからは試行が急増し、PHP2Shell はすでに広く悪用されている、と書いている。
Cloudflare、Patchstack、Hadrian、watchTowr なども、10/21 に試行を観測したと報告している。
一方で PHP Foundation は「公開時点で、実際の攻撃に使われている exploit は確認していない」としている。CISA の KEV(悪用が確認された脆弱性のカタログ)にも、記事の時点では載っていない。
記事の時点で、侵入に成功した具体的な事例の報告は見当たらない。とはいえ、PoC が出回って大量のスキャンが始まっている以上、更新していないサーバーは狙われている前提で動いたほうがいいと思う。
日本では、JPCERT/CC と IPA が 10/22 に注意喚起を公開した。海外では、CISA がすぐに更新できない場合や PHP 8.1 以前を使い続けている場合はシステムをオフラインにすべきだとし、英国の NCSC もオフラインにすることを検討するよう求めている。冒頭の高市首相の「ウェブサイト等を一時的に停止させることも有効策の一つ」という呼びかけも、同じ考え方になる。
まとめ
エンジニアでない人は、まず第1部と第2部の冒頭のボックスに書いたことを確認してほしい。以下は、サーバーを自分で管理しているエンジニア向けの確認項目になっている。
eMudhra の件で確認すること。
テスト用ホストに、curl と、実際にアプリが使っている言語のクライアントで接続して、証明書エラーになるか確かめる
OS の ca-certificates を更新する(macOS の /etc/ssl/cert.pem は未更新)
Go / Rust / Deno のバイナリは修正版で再ビルドする。Node.js と Java は本体を更新し、Electron 製のアプリはアプリの更新を待つ
Python は certifi と pip を更新する
コンテナイメージは、ベースイメージを pull し直して作り直す
更新したら、長時間動いているプロセスを再起動する
eMudhra の証明書を使っているサイトは、10/28 までに別の認証局の証明書に入れ替える
PHP2Shell で確認すること。
PHP を 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 以上に更新し、PHP-FPM や Apache を再起動する(ディストリビューションのパッケージは changelog で CVE 番号を確認する)
すぐ更新できないなら、session.upload_progress.enabled=0 などの緩和策を入れたうえで、できるだけ早く更新する
8.1 以前は、ディストリビューションの修正済みパッケージがあればまずそれを入れ、そのうえでサポートのあるバージョンへの移行を急ぐ
参考リンク
eMudhra の件。
emudhra.we-have-a-problem.com
Mozilla Bugzilla #2083449
Mozilla dev-security-policy のスレッド
Google のブログ
eMudhra の声明
PHP2Shell。
PHP の発表(php.net)
GHSA-w8hw-w9fx-j79w(CVE-2026-109618)
GHSA-6wmf-4rv5-p3rp(CVE-2026-109619)
PHP Foundation のブログ
Wiz の記事
Calif の記事
1 like
Mentions
Composerのdump-autoloadは--no-devの指定をどう判断しているのか はじめに Composerで本番環境向けに依存パッケージをインストールするとき、--no-devオプションを指定することがあります。 composer install --no-dev そのあとに、次のコマンドを実行したとします。 composer dump-autoload dump-autoloadコマンドには--no-devを指定していませんが、開発用のオートロード設定(autoload-dev)は除外されたままでした。 なぜ、このような動作なるのか気になったので、Composerの公式ドキュメントとソースコードを確認してみました。 環境 PHP 8.5.12 Composer 2.10.3 公式ドキュメントを確認する まず、Composerの公式ドキュメントを確認します。 getcomposer.org dump-autoloadコマンドの--dev及び--no-devオプションには次の説明があります。 Composer will by default infer this automatically according to the last install or update --no-dev state. どちらも、最後のinstallまたはupdateで指定された--no-devの状態から自動的に判断される、と書かれています。 つまり、dump-autoloadコマンドは--dev及び--no-devオプションが指定されていない場合、直前の状態で判断しているようです。 直前の状態で判断とは?この辺りはソースコードから読み解いていく方がよさそうです。 ソースコードを確認する Composerのソースコードを確認します。 dump-autoloadコマンドのDumpAutoloadCommandクラスの処理を順番に追いかけていくとAutoloadGeneratorクラスのdump()メソッドに次の処理があります。 github.com/composer/composer/blob/2.10.3/src/Comp… この処理を見ていきます。 1. devModeが未指定か確認する if (null === $this->devMode) { 最初に、$this->devModeがnullかどうかを確認しています。 $this->devModeがnullの場合は自動判定に進みます。 null以外の場合、--dev及び--no-devが明示的に指定されているため、自動判定の処理には入りません。 この$this->devModeに値を設定するのは、DumpAutoloadCommandクラスで行なっています。 github.com/composer/composer/blob/2.10.3/src/Comp… 2. installed.jsonを読み込む // we assume no-dev mode if no vendor dir is present or it is too old to contain dev information $this->devMode = false; $installedJson = new JsonFile($config->get('vendor-dir').'/composer/installed.json'); if ($installedJson->exists()) { $installedJson = $installedJson->read(); if (isset($installedJson['dev'])) { $this->devMode = $installedJson['dev']; } } 次に、vendor/composer/installed.jsonを読み込んでいます。 ファイルの存在確認を行なってから、installed.jsonの devの値を取得しています。 この値が存在する場合、$this->devModeに値を設定しています。 つまり、--dev及び--no-devオプションを指定していない場合は、installed.jsonのdevの値を使って判断していることになります。 installed.jsonのdevにはどんな値が入る? installコマンドを実行するとInstallCommandクラスが動くのでみてみると以下で --no-devオプションを取得し、設定していることがわかります。 github.com/composer/composer/blob/2.10.3/src/Comp… このsetDevModeメソッドを確認してみると引数の型はbool型になっていました。 github.com/composer/composer/blob/2.10.3/src/Comp… つまり、--no-devオプションがあればfalse、なければtrueを設定しています。 ※!$input->getOption('no-dev')と!がついているので意味が逆転します。 このあとの処理を順番に見ていきます。 github.com/composer/composer/blob/2.10.3/src/Comp… github.com/composer/composer/blob/2.10.3/src/Comp… github.com/composer/composer/blob/2.10.3/src/Comp… 最終的な書き込みは以下の場所で行われていました。 github.com/composer/composer/blob/2.10.3/src/Comp… ここまでの間で設定した値は書き換わっていないので、installed.jsonのdevにはbool値が入っていることがわかります。 この値をdump-autoloadコマンドが読み取ることで、開発用のオートロード設定を含めるかどうかが決まるようです。 まとめ dump-autoloadコマンドはinstalled.jsonのdevの値を見て、開発用のオートロード設定を含めるかどうか判断していることがわかりました。 ソースコードを追いかけてみて、またひとつComposerのことが詳しくなれました。
Done updating PHP? Composer 2.11 RC1 is available with a cooldown policy, terminal progress reporting via OSC 7501, and a whole lot of fixes including security checks against the compromised eMudhra certificates. Try it out now! github.com/composer/composer/releases/tag/2.11.0-… #composerphp
eMudhra の CA 鍵漏洩と PHP2Shell、同じ週に来た2つの緊急対応を一次ソースで整理する ! この記事は、2026/10/22 14:00(日本時間)までに公開された一次ソースをもとにまとめている。どちらの件も状況が変わり続けているので、作業の前にリンク先で最新の情報を確認してほしい。 10/21 の夜、高市首相が X にこんな投稿をしていた。 皆様に、今夜に対応して頂きたい大至急のお願いです。 多くのウェブサイトで使用されているPHPに関し、PHPのセキュリティチームが、重大な2件の脆弱性に関する注意喚起を行っています。 投稿は、23:00 に公開される修正パッチをすぐ適用できるよう準備してほしい、難しければウェブサイトを一時的に止めることも有効策の一つだ、と続く。首相が個別のソフトウェアの脆弱性について直接呼びかけるのは珍しく、ITmedia はエンジニアの反応まで記事にしていた。日経によると、首相自身のホームページもその夜から止めていたらしい。 この PHP の脆弱性(PHP2Shell)と同じ週に、もうひとつ、ブラウザ以外の TLS クライアントに広く関わる認証局の鍵の問題も明らかになっている。この記事では、2つの件をそれぞれ一次ソースで整理していく。 TL;DR この1週間で、性質のまったく違う緊急対応が2つ重なった。2つは別々の事件で、互いに関係はない。 eMudhra の中間 CA 鍵漏洩では、インドの認証局 eMudhra の中間 CA 証明書8枚について、秘密鍵を公開情報から誰でも計算できる状態だったことが分かった。この鍵があれば、任意のドメインの偽サーバー証明書を作れる。主要なブラウザは CT(後述)のおかげで偽証明書を受け付けないので、危ないのは Go / Java / Node.js / Python / Rust などで書いたプログラムや curl のような、ブラウザ以外のクライアントのほうだ。対策は言語ごとに違い、OS の更新だけでは済まないものも多い。 PHP2Shell(CVE-2026-109618 / CVE-2026-109619)は、認証なしでリモートからコードを実行できてしまう PHP 本体の脆弱性だ。修正版の PHP 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 は、10/21 の 23:00 ごろに公開された。mod_php ではアプリのコードが1行も動く前に攻撃が成立し、PHP-FPM などほかの構成も対象になる。設定で完全に塞ぐ方法はなく、更新するしかない。 PHP を使っているなら両方に関係がある。PHP2Shell の更新に加えて、PHP から外に出る HTTPS 通信(Composer や外部 API の呼び出し)が eMudhra の件の影響を受けないかも確認しておきたい。 第1部 eMudhra の中間 CA 鍵漏洩 ! エンジニアでない人が、まず確認しておきたいこと スマートフォンと PC の OS を最新にする。Apple などはまだ対応しきれていない可能性があるので、この先しばらくはアップデートが来たらすぐ入れる ブラウザと、普段使っているアプリ(Slack や VS Code など)を最新にする この件で危ないのは、主にサーバーや開発ツールだ。会社でサービスを運営しているなら、エンジニアに「この記事のまとめにある eMudhra の確認項目を済ませたか」を聞いてもらえばいい。 何が起きたのか この件の情報は、Mozilla の Dennis Jackson さんが公開した emudhra.we-have-a-problem.com というまとめページに集まっている。冒頭にはこう書かれている。 The private keys of eight eMudhra intermediate CA certificates have been compromised. They chain to roots trusted by the Mozilla, Microsoft, Apple and Chrome root programs and by many downstream trust stores. 8枚の中間 CA 証明書の秘密鍵が漏れていて、しかもそれらは主要なルートプログラムすべてが信頼するルートにつながっている、という内容だ。この問題を見つけて報告した Wayne さんは、各中間 CA の秘密鍵で We have a problem here - Wayne というメッセージに署名し、鍵を持っていることを証明していて、まとめページのドメイン名もこの署名メッセージから来ている。 Mozilla の Bugzilla #2083449 と各社の発表をもとに、時系列を日本時間で並べた。 日時(日本時間) 出来事 2025/4/30 eMudhra の鍵生成セレモニーで問題の鍵が作られる 2026/10/18 03:05 Wayne さんが Apple / Chrome / Microsoft / Mozilla / eMudhra に報告 10/18 04:45 Chrome が CRLSet(Chrome が配信する失効リスト)で TLS 用の中間 CA 6本をブロック 10/18 07:59 Firefox が OneCRL(Firefox が配信する失効リスト)でブロック(ブラウザの更新は不要) 10/18 18:24〜 eMudhra が8本を失効 10/19〜20 Sectigo がクロス署名版を失効。Apple がブロック 10/20〜21 Microsoft がブロック。Mozilla と Chrome がルート emSign ECC Root CA - G3 の緊急削除を決定。certifi・Go・Node.js などが 10/19〜21 にかけて修正版を公開 10/28(予定) Chrome Root Store v43 で emSign ECC Root CA - G3 を削除 対象の中間 CA は EM DV/OV/EV TLS CA - G3B、G3C の TLS 用6枚と、コード署名用の EM OV CS CA - G3B/G3C の2枚。それぞれに、eMudhra のルートから発行された版と、別の認証局 Sectigo のルート AAA Certificate Services(旧 Comodo AAA)が同じ鍵に署名した版(クロス署名)があるので、鍵は8本でも証明書としては16枚になる。フィンガープリントの一覧は impacted-intermediates.json にまとまっている。 鍵はどれくらい弱かったのか これが今回いちばん衝撃的なところだと思う。Mozilla の担当者が Bugzilla に書いた分析を引用する。 P384 private keys are randomly selected integers between 1 and the group order. The 8 impacted keys all used integers less than 256. That is, the private keys are effectively all-zeroes apart from the last byte. P-384 の秘密鍵は本来なら2の384乗に近い範囲からランダムに選ばれるが、今回の8本はどれも 256未満 で、最後の1バイト以外が全部ゼロだった。これなら1から255までを順に試せば必ず当たり、復元には1秒もかからない。同じコメントには、AI エージェントに「CTF をやっているので、この証明書の秘密鍵を復元して」と頼んだら一発で復元できた、という報告まである。 As this incident enables even technically unsophisticated individuals to easily recover the private keys for these intermediates, the impact of this incident could not be higher. なぜこんな鍵ができたのかについて、eMudhra は Bugzilla でこう説明している。 an approved deviation to our usual KGC to test a wrap/unwrap was introduced as these keys were meant for export for this instance c) a flaw in the code resulted in the second pair of keys being created onboard which were weaker these second pair of weaker keys were used by mistake to create the csr (because the key labels were similar) 鍵をエクスポートするための wrap/unwrap(鍵を暗号化して取り出す処理)をテストしたときに、コードの不具合で HSM の中に弱い鍵がもう1組作られ、ラベルが似ていたせいで間違ってそちらを CSR に使ってしまった、と説明している。eMudhra の公式声明によると、この状態は約18か月、2回の独立監査でも見つからなかったらしい。とはいえ同じ声明には「正確な根本原因はまだ確定していない」とも書かれていて、Chrome Root Program は eMudhra に12項目の質問を送っている。 何が危ないのか 秘密鍵を持っていれば、その中間 CA の名前で、任意のドメインのサーバー証明書を発行できる。たとえば api.github.com や pypi.org の偽証明書を作り、公衆 Wi-Fi や社内のプロキシ、DNS の乗っ取りなどで通信経路の途中に入り、中身を読んだり書き換えたりする中間者攻撃が成立してしまう。残りの2本はコード署名用で、Windows がこれを信頼していたため、偽の署名を付けたプログラムを作れてしまう可能性もあった。 ただし、ブラウザでは偽証明書を使った攻撃は成立しなかったと、まとめページは判断している。Chrome / Safari / Firefox / Edge は Certificate Transparency(CT)という公開ログに記録されていない証明書を受け付けず、問題の中間 CA から発行された証明書は CT ログに1枚も記録されていないからだ。 There are no entries in the certificate transparency logs for these intermediates in that period, indicating that CT-enforcing clients like Firefox, Chrome, Edge and Safari could not have been attacked. However, many clients outside of the browser ecosystem do not enforce Certificate Transparency. これに対して、curl や OpenSSL、各言語の HTTP クライアント、IoT 機器などは CT を確認しない。失効情報(CRL や OCSP)も、デフォルトでは確認しないものが多い。こうしたクライアントは、攻撃者が CT に記録せずに作った偽証明書を、そのまま受け入れてしまう。しかも鍵が弱かったのは2025年4月の生成時点からなので、その間に悪用されたかどうかは誰にも分からない。 まとめページは、問題の中間 CA の証明書をわざと使ったテスト用ホストを立てていて、そこへの接続に成功したクライアントの統計も公開している。10/22 13:30(日本時間)の時点で、直近24時間の接続成功は約16.9万回あり、UA(クライアントが名乗る名前)別に見ると、iOS の WebView や Safari が上位に並び、そのあとに macOS 標準の curl のバージョンである curl/8.7.1 が続いている。 iOS が上位にいるのは意外かもしれない。まとめページは Apple も 10/19 にブロックしたとしているが、統計ではテスト用ホストのうち eMudhra のルート経由のチェーンに iOS からの接続成功が集中している。iOS の信頼ストアの更新は、まだ完全ではないのかもしれない。CT に記録されていない偽証明書なら Safari は受け付けないが、iOS のアップデートが来たら早めに入れておきたい。 macOS 26.6.2 の標準の /usr/bin/curl でテスト用ホストに接続すると普通につながり、Your client successfully connected to the site. That's bad! と返ってきてしまった。macOS の標準の curl、git、python3、perl、ruby が参照する /etc/ssl/cert.pem が、この時点ではまだ更新されていないことが原因になっている。 巻き添えで正規の証明書も止まる eMudhra から正規に証明書を買っていたサイトにも影響が出る。Mozilla と Chrome はルート emSign ECC Root CA - G3 ごと信頼を外すと決めたので、その配下の正規の証明書も信頼されなくなる。 After discussion with maintainers downstream of Mozilla's Root Store, we have decided that the circumstances warrant the emergency removal of trust in emSign ECC Root CA - G3. This will protect clients which do not use revocation information or lack a mechanism to withdraw trust in specific intermediates. Chrome の集計では、影響を受ける有効な証明書は約3万枚で、その99.9%は、米国の大学向けの証明書サービス InCommon の下位 CA から発行されたものだった。eMudhra は G1(RSA)系のルートへの移行を進めていて、Google はサイト運営者に別の認証局の証明書へすぐ切り替えるよう求めている。eMudhra の証明書を使っているサイトの運営者は、Chrome Root Store からルートが外れる 10/28 までに証明書を入れ替える必要がある。 修正の方式は2通りあるが、利用者が選ぶ必要はない ここからは、言語やツールごとの対応を見ていく。先に結論を書いておくと、ここで紹介する2つの方式は各プロジェクトが修正版の中で採った方式の違いで、利用者がどちらかを選ぶ必要はない。使っている言語やライブラリを修正版にし、Go や Rust のようにビルドして作るものは作り直せば、そのツールの方式で対策が入る。とはいえ、方式によって「OS の更新だけで足りるか」が変わってくるので、仕組みを知っておくと更新の漏れに気づきやすいと思う。 1つ目は、侵害された8本の公開鍵(SPKI)を拒否するリストを、検証の処理に組み込む方式だ。Go、Node.js、rustls-webpki(Rust)、Deno、Electron がこの方式をとり、Composer 本体も同じ仕組みを開発版に入れている。証明書ではなく公開鍵で判定するので、Sectigo のクロス署名版もまとめて拒否でき、OS の証明書ストアを使う設定でも有効になる。 2つ目は、同梱している CA バンドルからルート証明書を削除する方式で、Python の certifi、Rust の webpki-roots、Python のパッケージマネージャ uv、Elixir の castore、Perl の Mozilla::CA、composer/ca-bundle、Bun、Homebrew がこちらにあたる(どれも Mozilla のストアをもとにした CA バンドルを同梱している)。この方式は、そのバンドルを実際に使っている場合にしか意味がない。 利用者の目線で整理すると、1つ目の方式は、ツールやライブラリを修正版にすれば OS の設定に関係なく対策が入る。2つ目の方式は使い方で変わり、同梱のバンドルを使っていればツールの更新、OS のストアだけを使う設定なら OS の更新で直り、pip や Node.js の --use-system-ca のように両方を併用するツールなら両方の更新が要る。 つまり、利用者がやることは次の3つで足りると思う。 使っている言語・ライブラリを修正版にし、Go や Rust などビルドするものは作り直す OS の証明書を更新し、コンテナはイメージを作り直す 更新したら、長時間動いているプロセスを再起動する Java はどちらの方式とも違い、blocked.certs というファイルで証明書を1枚ずつブロックしていて、OS のパッケージで入れた JDK なら OS の更新で足り、単体で配布されている JDK は本体の更新が必要になる。macOS の /etc/ssl/cert.pem や RHEL のように修正がまだ出ていない環境は、後述の回避策を使う。他社が配布している Go 製の CLI や Electron アプリは利用者の側では直せないので、配布元の更新を待つしかなくなってしまう。 certifi のメンテナは、2つ目の方式しかとれない理由をこう書いている。 there's no facility for revoking an intermediate only もうひとつ気をつけたいのが、Node.js の --use-system-ca や pip(24.2 以降)のように、同梱バンドルに OS の証明書ストアを追加して使うツールだ。OS を更新してルートが消えても、古い同梱バンドルにルートが残っていれば、信頼されたままになってしまう。Node.js のドキュメントにも次のように書かれている。 Node.js currently does not support distrust/revocation of certificates from another source based on system settings. 言語・ランタイム別の対応状況 対象 修正版 仕組み やること Go 1.27.3 / 1.26.10(10/20) crypto/x509 に侵害された中間 CA の拒否リスト(CVE-2026-111943) 修正版の Go で再ビルドして再デプロイ Node.js 22.23.4 / 24.22.1 / 26.12.1(10/21) NSS 3.131.1 のルート更新と、SPKI 拒否リストの両方 Node 本体を更新。コンテナはイメージを作り直す Java (OpenJDK) advisory は 27.0.1 / 25.0.5 / 21.0.13 / 17.0.21 / 11.0.33 / 8u512 以前を影響ありとしている(CVE-2026-91403) blocked.certs で証明書を個別にブロック 単体配布の JDK は更新。OS パッケージの JDK は OS の証明書更新で足りる、と advisory にある Python certifi 2026.10.18 / 2026.10.19 10.18 で emSign のルートをまとめて削除し、10.19 で影響のない3本を戻した。いま外れているのは emSign ECC Root CA - G3 pip install -U certifi。requests は certifi しか見ないので必須 pip 26.2.2(10/20) 同梱の certifi を更新 python -m pip install -U pip uv 0.13.4(10/20) 同梱バンドルからルートを削除 uv self update rustls-webpki 0.103.16(10/20) SPKI 拒否リスト cargo update -p rustls-webpki して再ビルド webpki-roots 1.0.10(10/19) ルートを削除 cargo update して再ビルド Deno 2.9.8(10/21) rustls-webpki と webpki-roots の修正を取り込み deno upgrade。deno compile したバイナリは作り直す Electron 44.9.1 / 43.8.1 / 42.11.16(10/20) SPKI 拒否リスト アプリ開発者が更新して再配布 Bun 修正は main にマージ済みで、リリースは未公開 ルートを削除 次のリリースを待つ Elixir castore 1.0.22(10/20) ルートを削除 mix deps.update castore Perl Mozilla::CA 20261020 ルートを除外 cpanm Mozilla::CA Homebrew ca-certificates 2026-10-20 ルートを除外 brew upgrade ca-certificates。Homebrew の curl / OpenSSL / Python が参照する Ruby / .NET / CPython の ssl 本体の修正なし 多くの環境で OS のストアを使う OS の証明書を更新する 表の中では Electron が見落としやすい。Chrome は CRLSet という仕組みでブロックリストを配信しているが、Electron はこれを受け取らないので、Chromium を内蔵していても Chrome と同じ保護は受けられない。Electron の PR にもそのまま書かれている。 add entries to the compiled-in SPKI blocklist that Chrome ships via CRLSet, which Electron does not consume. Java のバージョン番号は、まとめページの表(8u511 など)と OpenJDK の advisory(8u512 以前が影響)で食い違っていて、記事の時点では確定できなかった。Oracle JDK の情報も確認できていないので、Java を使っている人は配布元で直接確認してほしい。 OS・ディストリビューション別の対応状況 対象 修正版 内容 Ubuntu USN-8944-1(22.04 以降は 20260816ubuntu0.<リリース番号>.1)、USN-8944-2(ESM) emSign ECC Root CA - G3 を削除。ESM 版は Comodo AAA も削除 Debian DSA-6572-1(trixie 20250419+deb13u1)、DLA-4845-1(bookworm 20250419~deb12u2) G3 と Comodo AAA を無効化 Fedora ca-certificates-2026.2.92_v9.0.319 G3 と AAA を削除 RHEL 6〜10 記事の時点で RHSA は未公開 当面は2つのルートを手動でブロックするよう案内している Alpine ca-certificates 20261020-r0 上流の更新に追従してルートを削除 Arch ca-certificates-mozilla 3.131.1-1 同上 FreeBSD SA-26:73 G3 を untrusted に curl の cacert.pem 2026-10-20 版 Mozilla のストアに追従 macOS /etc/ssl/cert.pem は未更新 後述の回避策を参照 Windows Microsoft の自動更新(Disallowed CTL)で配信済み ルートはそのままで、中間 CA の証明書をブロック(まとめページによると16枚) Ubuntu の通常版が Comodo AAA を無効化していないのは、Mozilla のストアにこのルートがすでに入っておらず、最新の ca-certificates にも含まれていないためだ。古いバンドルを使い続けている ESM 版や Debian、Fedora は、念のため AAA も無効化している。 RHEL と Amazon Linux の ca-certificates の更新と、Android の公式発表は、記事の時点では見当たらない。 どの OS でも、ca-certificates を更新したあとは、長時間動いているプロセス(Java や Node.js のサーバーなど)を再起動しておきたい。起動時に読み込んだ証明書を持ち続けるプログラムがあるからだ。 コンテナは作り直さないと直らない コンテナイメージには、ビルドした時点の ca-certificates が入っている。ホストの OS を更新してもコンテナの中は古いままなので、イメージを作り直す必要がある。 Docker の公式イメージは、Debian を 10/20 に、Alpine を 10/21 に更新している。Debian のベースイメージには ca-certificates が入っていないので一見関係なさそうだが、派生イメージの再ビルドを促すために、あえて更新したらしい。 The Debian images don't contain ca-certificates, but many downstream images do… updating Debian is the simplest way to trigger downstream rebuilds. node:24 や python:3.14 のような浮動タグを使っている場合も、docker pull し直してからビルドしないと古いレイヤーが使われてしまうので注意したい。 PHP の場合 PHP 本体(php-src)にはこの件の修正は入っていないが、openssl 拡張も curl 拡張も、OS の証明書ストアか、openssl.cafile / curl.cainfo で指定したファイルを見る作りなので、OS の ca-certificates を更新すれば対策になる。 では、Composer まわりはどうか。composer/ca-bundle は 1.6.0 / 1.4.16 で同梱の cacert.pem から emSign ECC Root CA - G3 を抜いた。ただ、CaBundle::getSystemCaRootBundlePath() は SSL_CERT_FILE、openssl.cafile、OS の既知のパスの順に探し、同梱ファイルは最後の手段としてしか使わないので、OS のストアが見つかる普通の環境では、この削除の影響はほぼないと思う。PR の本文にも、次のように書かれている。 Removing the root from our bundle does not help users whose system CA store is used, so clients like Composer can use this to reject such connections. そのため ca-bundle には、SPKI でチェーンを判定する CaBundle::findDistrustedCertificate() という API が追加され、これを使って Composer 本体が接続を拒否する PR #13146 も 10/21 に main にマージされたものの、記事の時点ではまだリリースされていない。それまでは、Composer を実行するマシンの OS の証明書を更新しておくのが確実だと思う。 ちなみに、Guzzle は composer/ca-bundle に依存しておらず、デフォルトでは OS のストアを使う。WordPress が使っている HTTP ライブラリの WordPress/Requests は、2.0.21 で対応済みだ。 自分の環境が影響を受けるか確認する いちばん手軽なのは、まとめページが用意しているテスト用ホストに、普段使っているクライアントで接続してみることだ。 curl dv-g3b-emudhra.we-have-a-problem.com curl dv-g3b-aaa-emudhra.we-have-a-problem.com 証明書エラー(curl: (60) など)になれば安全で、Your client successfully connected to the site. That's bad! が返ってきたら、まだ問題の中間 CA を信頼している。上が eMudhra のルート経由、下が Sectigo のクロス署名経由のチェーンなので、両方試すのがいいと思う。 curl だけでなく、アプリが実際に使っている言語で同じ URL にアクセスしてみるほうが確実だ。 Python (requests) python -c "import requests; print(requests.get('dv-g3b-emudhra.we-have-a-problem.com').text)" Node.js node -e "fetch('dv-g3b-emudhra.we-have-a-problem.com').then(r=>r.text()).then(console.log)" PHP php -r "echo file_get_contents('dv-g3b-emudhra.we-have-a-problem.com');" どれも、エラーで落ちれば安全だ。 証明書バンドルのファイルに、問題のルートが残っているかを直接見ることもできる。 B=/etc/ssl/certs/ca-certificates.crt # RHEL 系は /etc/pki/tls/certs/ca-bundle.crt、macOS は /etc/ssl/cert.pem awk '/-----BEGIN CERTIFICATE-----/{c=""} {c=c $0 "\n"} /-----END CERTIFICATE-----/{cmd="openssl x509 -noout -subject -fingerprint -sha256 | paste - -"; printf "%s", c | cmd; close(cmd)}' "$B" \ | grep -E "emSign ECC Root CA - G3|AAA Certificate Services" || echo "not found (OK)" not found (OK) と出れば、そのバンドルには残っていない。 OS の更新が来ていないときの回避策 まとめページには、更新が出ていない環境向けの回避策が載っている。とはいえ、ページ自身が上級者向けとしていて、Linux 向けの手順には一般のユーザーにはおすすめしないとも書かれているので、自分で戻せる人だけが使ってほしい。以下はまとめページのコマンドをそのまま引用している。 macOS の /etc/ssl/cert.pem から2つのルートを外す場合(バックアップを取ってから書き換える)。 sudo cp -p /etc/ssl/cert.pem /etc/ssl/cert.pem.bak && sudo awk '/^(###|===) /{skip=0} /^=== .*\/CN=(AAA Certificate Services|emSign ECC Root CA - G3)$/{skip=1} !skip' /etc/ssl/cert.pem.bak | sudo tee /etc/ssl/cert.pem > /dev/null Debian / Ubuntu の場合。 sed -i \ -e 's|^mozilla/emSign_ECC_Root_CA_-_G3.crt|!&|' \ -e 's|^mozilla/Comodo_AAA_Services_root.crt|!&|' \ /etc/ca-certificates.conf && update-ca-certificates Fedora / RHEL / Rocky / Alma / Amazon Linux 2023 の場合。 d=/etc/pki/ca-trust/source/blocklist; [ -d $d ] || d=/etc/pki/ca-trust/source/blacklist trust extract --overwrite --format=pem-bundle \ --filter='pkcs11:object=Comodo%20AAA%20Services%20root;type=cert' \ $d/Comodo_AAA_Services_root.pem && trust extract --overwrite --format=pem-bundle \ --filter='pkcs11:object=emSign%20ECC%20Root%20CA%20-%20G3;type=cert' \ $d/emSign_ECC_Root_CA_-_G3.pem && update-ca-trust Comodo AAA まで外すと、正規の Sectigo の証明書が壊れないか気になるところだと思う。Chrome はこのルートを2025年4月に削除していて、Mozilla のストアにもすでに入っていない。AAA のクロス署名つきチェーンを返す Sectigo のサイトに、AAA を抜いたバンドルで接続してみると、新しい OpenSSL / LibreSSL は、別の正規のルートまでチェーンを構築し直して問題なく接続できた。かなり古い OpenSSL のようにチェーンを構築し直さないクライアントでは、失敗することもあると思う。 Windows は自動更新でブロックが配信されているので通常は何もしなくてよく、自動更新を受け取らない端末向けには、まとめページに PowerShell スクリプトが用意されている。 第2部 PHP2Shell ! エンジニアでない人が、まず確認しておきたいこと レンタルサーバー(さくら、ロリポップ!、エックスサーバーなど)でサイトを運営しているなら、管理画面で PHP のバージョンを確認する。8.1 以前なら、バックアップを取ってから 8.2 以上に切り替える。8.2 以上なら、事業者のお知らせで修正済みとなっていれば作業は終わり VPS や自社のサーバーで動かしているなら、エンジニアに「PHP を修正版に更新して、PHP-FPM や Apache を再起動したか」を確認してもらう なお、WordPress 本体を最新にしても、この脆弱性は直らない。直す必要があるのはサーバー側の PHP だ。 何が起きたのか こちらは PHP 本体の脆弱性で、CVE-2026-109618 と CVE-2026-109619 の2件をまとめて PHP2Shell と呼んでいる。どちらも CVSS v4.0 で 9.2。PHP の公式発表では、影響する範囲をこう書いている。 Who is at risk: all PHP installations serving web requests, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. We consider the risk highest for mod_php, with a demonstrated exploit where an unauthenticated request can trigger the attack before any application code runs. Web リクエストを処理しているすべての PHP が対象で、とくに mod_php では、認証なしのリクエストで、アプリのコードが動く前に攻撃が成立することが検証環境で実証されている。cron やコマンドラインだけで PHP を使っている場合については、公式は個別に触れていない。 経緯を PHP Foundation のブログと各社の公開記事をもとに並べた。 日時 (JST) 出来事 2024年 外部監査(Quarkslab)の指摘を修正していた PHP のコア開発者が、CVE-2026-109618 の原因になる OOM の問題の最初の兆候に気づく 2026年8月 Calif と OpenAI が 8/11 に、Wiz が 8/24 に、それぞれ独立に PHP へ報告 10/21 00:00 頃 CVE 番号が SNS やフォーラムで出回り始める(誤った CVSS 10.0 つき) 10/21 04:30 PHP が事前告知。当初の予定(10/22)を1日前倒しし、10/21 23:00 JST にリリースすると発表 10/21 05:00 頃 Calif が PoC の動画を誤って公開した(PHP Foundation による) 10/21 16:41 Chainguard が修正入りのコンテナイメージを先行して公開。PHP Foundation は、情報公開の取り決め(エンバーゴ)を破ったと批判している 10/21 22:34 GitHub Security Advisory 公開 10/21 23:00 ごろ 修正版を公開(予告は 23:00 だったが、実際の公開は数分〜十数分ほど早かった) 情報が予定より早く漏れたため、リリースを1日前倒しした。PHP Foundation は、ディストリビューションのパッケージングがまだ終わっていない中での判断だったと書いている。 Moving the release forward by one day was the best compromise between acting quickly, giving people time to prepare, and making sure everyone had a simple update path when the vulnerabilities were disclosed. 2つの脆弱性の中身 公式の GHSA によると、2件の内容はこうなっている。 CVE-2026-109618(GHSA-w8hw-w9fx-j79w「RCE via OOM corruption」)。PHP はメモリ不足(OOM)のとき、longjmp() で処理を強制的に抜ける。ところが、リクエスト用のメモリが初期化しきれていない途中でメモリ確保が失敗すると、壊れた状態のままリクエストの終了処理に進んでしまう。攻撃者は、post_max_size の範囲に収まる multipart リクエストで、各パートのヘッダーを大量に送ったり、空のファイル欄をネストさせたりして、意図的に memory_limit を使い切らせる。mod_php では、この一連の流れがアプリのコードの実行前に起きる。 CVE-2026-109619(GHSA-6wmf-4rv5-p3rp「RCE via stale global state」)。PHP のワーカーは、前のリクエストの状態をグローバル変数に持っていて、次のリクエストの前にリセットする。前のリクエストが致命的エラーで落ちるとそのリセットが飛び、解放済みのメモリを指したままの状態が残る。次のリクエストが通常の初期化より前にそれを触ると、use-after-free になる。確認されている経路のひとつが session upload progress で、これはデフォルトで有効、しかもアプリが session_start() を呼んでいなくても経路になる。 修正は両方まとめて1つのコミット("Avoid state corruption via bailout")に入っているので、どちらか片方だけ直す、という選択肢はない。 発見者の Wiz の記事では CVE 番号の割り当てが公式と逆になっている(upload progress の経路を 109618 としている)。この記事では公式の GHSA の割り当てに合わせた。 どの構成が危ないのか 公式の GHSA に書かれた内容を、実行方式(SAPI)ごとに表にした。 SAPI CVE-2026-109618 CVE-2026-109619 Apache + mod_php アプリに依存しない RCE を実証済み 実証済み PHP-FPM ソース解析上は影響あり。完全な攻撃はまだ実証されていない session upload progress 経由で実証済み。成功するかはアプリの処理内容にも左右される FrankenPHP アプリに依存しない攻撃が成立する可能性が高い デフォルト構成では未確認 LiteSpeed 可能性あり(未検証) 条件次第 デフォルトの memory_limit(128M)と post_max_size(8M)のままで RCE が成立したと書かれているので、デフォルト設定のままのサーバーもそのまま対象になると考えたほうがよく、Wiz も「Hello World だけのアプリでも影響を受けうる」と書いている。nginx + PHP-FPM の構成でも、アプリに依存しない攻撃がまだ見つかっていないだけで、安全が確認されたわけではない。実際、PHP Foundation のブログは、CVE-2026-109618 についても PHP-FPM でアプリ側の処理を経由した RCE を確認したと書いていて、GHSA の記述より一歩踏み込んでいる。 影響を受けるバージョンと直し方 公式の advisory が影響ありとしているのは、次の修正版より前のバージョンだ。 PHP 8.5.12 未満 PHP 8.4.27 未満 PHP 8.3.36 未満 PHP 8.2.35 未満 php.net の advisory が挙げているのはサポート中の 8.2〜8.5 だけだが、古いバージョンが安全という意味ではない。発見者の Wiz と Calif は PHP 5.4 以降のほぼすべてが影響を受けるとしていて、Google Cloud のセキュリティ情報も 5.4〜8.5 を対象として扱っている。PHP のセキュリティチーム自身も、サポートが終わった 7.4 / 8.0 / 8.1 向けにソースのパッチを用意していて、後述のとおり、ディストリビューションも古いバージョンに修正を入れている。 PHP 8.1 and older no longer receive updates from the PHP project. 対策は、上の修正版(またはディストリビューションの修正済みパッケージ)に更新することしかない。PHP の公式発表にも、はっきりそう書かれている。 There are no complete mitigations, updating is the only safe choice. バージョンを確認するときは、php -v で表示されるのが CLI の版だという点に注意したい。Web で実際に動いている PHP-FPM や mod_php が別のバージョンのこともあるので、php-fpm -v や、一時的に置いた phpinfo() で確かめるといい(確認したら phpinfo() は消しておく)。ディストリビューションによっては、コマンド名が php-fpm8.3 のようにバージョンつきになっている。更新したあとは、PHP-FPM や Apache を再起動しないと古いプロセスが動き続けるので、再起動まで済ませてほしい。 ディストリビューションのパッケージは、修正をバックポートしていてバージョン番号が upstream と一致しないことがあるので、その場合はパッケージの changelog に CVE 番号が載っているかで判断する。Docker の公式イメージには php:8.5.12-fpm などのタグが 10/22 未明(JST)に出ているが、php:8.4 のような浮動タグは pull し直さないと古いままだ。remi のリポジトリは、当日中には更新しないと告知されていた。 すぐ更新できないときの緩和策 公式は、いくつかの緩和策を挙げつつ、どれも「特定の攻撃経路を減らすだけで、安全にはならない」と念を押している。 If you cannot update immediately: while only an update is a complete solution, the following measures reduce exposure to specific attack paths but do not make an installation safe. 挙げられている主なものはこのあたりになる。 session.upload_progress.enabled=0 にして、全ワーカーを再起動する。php.ini や FPM のプール設定など、リクエストの解析より前に読み込まれる場所で設定する必要があり、ini_set() や .user.ini では意味がない。これで塞がるのは CVE-2026-109619 の確認済みの session 経路だけ。 PHP 8.5 では fatal_error_backtraces=0 にする。 memory_limit=-1 をアプリから上書きできない形で設定する。とはいえ、OS 側のメモリ確保失敗では同じ経路に入りうると書かれている。メモリの上限がなくなるので、サーバー全体のメモリを使い切られないよう、コンテナや cgroup の上限とあわせて使う。 post_max_size を下げ、フロント(リバースプロキシや WAF)でリクエストのサイズ、パーツ数、ヘッダー数を制限する。multipart を使わないアプリなら、フロントで multipart を止める。 パッチを当てたあとも、upload progress の機能を使っていないなら無効のままにしておくことを GHSA はすすめている。 ディストリビューションとホスティングの対応 主なディストリビューションは、10/21〜22 にかけて更新を公開している。バックポートで修正しているため、バージョン番号が upstream と違うものが多い。 提供元 修正版の例 備考 Debian trixie 8.4.27-1~deb13u1(DSA-6574-1)、bookworm 8.2.35-1~deb12u1(DLA-4848-1) forky / sid は修正版 8.4.27-1 がアップロード済みで、記事の時点では反映待ち Ubuntu 24.04 8.3.6-0ubuntu0.24.04.13、22.04 8.1.2-1ubuntu2.28 など 番号は古いままで修正入り RHEL 記事の時点で確認できたのは RHEL 8 の php:7.4 向けのみ ほかのストリームは AlmaLinux が先行して出している AlmaLinux 全ストリームで .alma.1 つきの版 Red Hat より先に出している Amazon Linux 2023 php8.2〜8.5 で ALAS2023-2026-3301〜3304 php8.1 と AL2 core は修正予定なし Alpine php83 8.3.36-r0、php84 8.4.27-r0、php85 8.5.12-r0 cPanel(CloudLinux) ea-php52〜ea-php85 を更新 ea-php84 は 8.4.26 のまま修正入り、と明記されている ondrej/php PPA 8.5.12-1 などに加え、5.6〜8.1 の EOL 版にも修正版 Docker 公式 php イメージ 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 のタグ 浮動タグは pull し直す AlmaLinux のブログにも、確認は php -v ではなくパッケージのバージョンで、と書かれている。RHEL 系なら rpm -q php-common、Debian 系なら dpkg -l | grep php でバージョンを調べ、changelog に CVE 番号が載っているかを確かめるのがいいと思う。 クラウドの PaaS も対応を進めていて、AWS は Elastic Beanstalk の PHP プラットフォームと Lightsail の blueprint の更新を案内している(Lightsail の既存インスタンスは作り直して移行する必要がある)。Google Cloud は App Engine や Cloud Run で、自動更新を有効にしていない場合は再デプロイが必要としている。Azure App Service(Linux)と Heroku も 10/21 に修正版を公開した。 国内のレンタルサーバーでは、さくらのレンタルサーバが 10/21 23:00〜10/22 06:30 の緊急メンテで PHP を更新し、ロリポップ!は予防措置として一部のサービスを止めてメンテナンスに入っていた。レンタルサーバーやマネージドの環境では事業者が対応することが多いが、古い PHP のバージョンを選んでいる場合は切り替えを求められることがあるので、管理画面のお知らせは見ておくと安心だと思う。 アプリ側では、WordPress が「WordPress 本体の更新は不要で、予定もない」と発表し、Drupal も PHP の更新が唯一の完全な対策だとしている。PHP2Shell は WordPress ではなくサーバー側の PHP の脆弱性なので、WordPress を最新版にしても対策にはならない。 WAF での暫定対応 Cloudflare は、修正版公開の約11時間前にあたる 10/21 12:02(日本時間)から、無料プランも含めてデフォルトで保護ルールを有効にしている。AWS WAF、Akamai、Fastly もルールを公開していて、AWS のブログでは、PHPSESSID と PHP_SESSION_UPLOAD_PROGRESS を両方含む POST を止めるカスタムルールが紹介されている。ただ、Cloudflare は攻撃者がペイロードを書き換えて回避を試みているとも報告しているので、WAF はあくまで更新までのつなぎと考えたほうがよさそうだ。 悪用はされているのか 悪用の状況は情報が錯綜しているので、攻撃の試行が観測された話と、侵入に成功した話を分けて読む必要がある。 AWS は、公開前の 10/17 からハニーポットで試行を観測していたと発表した。その試行が成功したかは不明としつつ、10/21 11:00(日本時間)ごろに PoC が出回ってからは試行が急増し、PHP2Shell はすでに広く悪用されている、と書いている。 Cloudflare、Patchstack、Hadrian、watchTowr なども、10/21 に試行を観測したと報告している。 一方で PHP Foundation は「公開時点で、実際の攻撃に使われている exploit は確認していない」としている。CISA の KEV(悪用が確認された脆弱性のカタログ)にも、記事の時点では載っていない。 記事の時点で、侵入に成功した具体的な事例の報告は見当たらない。とはいえ、PoC が出回って大量のスキャンが始まっている以上、更新していないサーバーは狙われている前提で動いたほうがいいと思う。 日本では、JPCERT/CC と IPA が 10/22 に注意喚起を公開した。海外では、CISA がすぐに更新できない場合や PHP 8.1 以前を使い続けている場合はシステムをオフラインにすべきだとし、英国の NCSC もオフラインにすることを検討するよう求めている。冒頭の高市首相の「ウェブサイト等を一時的に停止させることも有効策の一つ」という呼びかけも、同じ考え方になる。 まとめ エンジニアでない人は、まず第1部と第2部の冒頭のボックスに書いたことを確認してほしい。以下は、サーバーを自分で管理しているエンジニア向けの確認項目になっている。 eMudhra の件で確認すること。 テスト用ホストに、curl と、実際にアプリが使っている言語のクライアントで接続して、証明書エラーになるか確かめる OS の ca-certificates を更新する(macOS の /etc/ssl/cert.pem は未更新) Go / Rust / Deno のバイナリは修正版で再ビルドする。Node.js と Java は本体を更新し、Electron 製のアプリはアプリの更新を待つ Python は certifi と pip を更新する コンテナイメージは、ベースイメージを pull し直して作り直す 更新したら、長時間動いているプロセスを再起動する eMudhra の証明書を使っているサイトは、10/28 までに別の認証局の証明書に入れ替える PHP2Shell で確認すること。 PHP を 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 以上に更新し、PHP-FPM や Apache を再起動する(ディストリビューションのパッケージは changelog で CVE 番号を確認する) すぐ更新できないなら、session.upload_progress.enabled=0 などの緩和策を入れたうえで、できるだけ早く更新する 8.1 以前は、ディストリビューションの修正済みパッケージがあればまずそれを入れ、そのうえでサポートのあるバージョンへの移行を急ぐ 参考リンク eMudhra の件。 emudhra.we-have-a-problem.com Mozilla Bugzilla #2083449 Mozilla dev-security-policy のスレッド Google のブログ eMudhra の声明 PHP2Shell。 PHP の発表(php.net) GHSA-w8hw-w9fx-j79w(CVE-2026-109618) GHSA-6wmf-4rv5-p3rp(CVE-2026-109619) PHP Foundation のブログ Wiz の記事 Calif の記事