PHP 8.4.24 で直った2件は、影響範囲がまったく違う
同じ日に、同じ製品の、同じ修正リリースで直った脆弱性が2件ある。どちらも NVD が CVSS 3.1 で 9.8 Critical を付けている。並べて見ると、同じ重さの問題が2つあるように見える。
実際には、この2件は影響を受ける範囲がまったく違う。片方は PHP 8.2 系まで遡り、Debian は 7.4 系にも修正を入れている。もう片方は 8.4.3RC1 で入った回帰なので、8.2 系・8.3 系はそもそも該当コードを持っていない。
PHP 8.4.24 / 8.5.9 で修正された CVE-2026-17543 と CVE-2026-17544 の話である。この記事では、2件の成立条件がどう違うのかを整理し、最後に自分の環境がどちらに当たるのかを判定するシェルスクリプトを置く。
前提: この2件は何か
どちらも 2026年7月30日に NVD へ公開された。採番元(CNA)は PHP で、php-src の GitHub Security Advisory が一次情報である。
| CVE-2026-17543 | CVE-2026-17544 | |
|---|---|---|
| 場所 | PostgreSQL 拡張(ext-pgsql) | BCMath 拡張(ext-bcmath) |
| 種別 | CWE-89 SQL インジェクション | CWE-787 領域外書き込み |
| 影響版 | 8.2.0〜8.2.32 / 8.3.0〜8.3.32 / 8.4.0〜8.4.23 / 8.5.0〜8.5.8 | 8.4.0〜8.4.23 / 8.5.0〜8.5.8 |
| 修正版 | 8.2.33 / 8.3.33 / 8.4.24 / 8.5.9 | 8.4.24 / 8.5.9 |
| 公式アドバイザリ | GHSA-7qpv-r5mr-78m4 | GHSA-x692-q9x7-8c3f |
CVSS の付き方には注意がいる。CNA である PHP は CVSS 4.0 で両方 8.1 High を付けているが、NVD は独自評価(Primary)として CVSS 3.1 で両方 9.8 Critical を付けている。数字だけを転記すると、どちらの物差しで話しているのか分からなくなる。本稿では NVD の Primary 評価(9.8)を採り、その旨を明記する。
CVE-2026-17543: エスケープの前提が2つずれている
こちらのほうが面白い。原因は「エスケープ関数のバグ」ではなく、エスケープ関数の仕様と、その結果を埋め込む場所の仕様が食い違っていたことにある。
公式アドバイザリの説明を追う。php_pgsql_convert() は、PHP 側の配列を SQL の値へ変換する内部関数である。文字列のエスケープには libpq の PQescapeStringConn() を使う。
ここで PostgreSQL 側の事情が入ってくる。PostgreSQL 9.1 以降、standard_conforming_strings の既定値は on である。この設定では、通常の文字列リテラル '...' の中でバックスラッシュは特別な意味を持たない。ただの文字である。したがって PQescapeStringConn() がバックスラッシュをエスケープしないのは、仕様どおりの正しい振る舞いである。
問題は埋め込み先だった。php_pgsql_convert() は値を E'...' 形式に入れて組み立てる。これは「エスケープ文字列定数」と呼ばれる形式で、こちらではバックスラッシュがエスケープ文字として解釈される。
つまり:
PQescapeStringConn()は「バックスラッシュは素通しでよい」という前提で動くE'...'は「バックスラッシュはエスケープ文字である」という前提で読む
この2つを繋ぐと、攻撃者が \ を送り込んだ場合に、後続の ' がリテラルの終端として解釈されない、あるいはその逆が起きる。アドバイザリの言葉では「バックスラッシュに続けて単一引用符を注入することで、文字列リテラルから抜け出せる」となる。そこから先は任意の SQL を継ぎ足せるので、trivial SQL injection(自明な SQL インジェクション)と表現されている。
どちらの関数にもバグは無い。組み合わせが間違っていたという形の欠陥である。
影響するのは4関数だけ
php_pgsql_convert() を経由するのは、次の4つだけである。
pg_insert()pg_update()pg_select()pg_delete()
いずれも「連想配列をテーブルの行に写す」用途の関数だ。pg_query_params() のようにサーバ側へパラメータを渡す関数や、PDO のプリペアドステートメントは経路が違うので該当しない。
さらに、そもそも ext-pgsql を読み込んでいない環境は無関係である。PostgreSQL を PDO_pgsql だけで使っている構成はここに含まれない。php -m に pgsql が出るかどうかが最初の分岐になる。
Debian は 7.4 系にも修正を入れている
もうひとつ、NVD の影響版一覧だけを見ていると見落とす点がある。Debian のセキュリティトラッカーを見ると、本件は php7.4(bullseye)についても修正対象として扱われており、7.4.33-1+deb11u12 が DLA-4733-1 で出ている。
Debian の対応状況は次のとおりである(2026年8月23日時点)。
| リリース | パッケージ | 修正版 | 告知 |
|---|---|---|---|
| bullseye | php7.4 | 7.4.33-1+deb11u12 | DLA-4733-1 |
| bookworm | php8.2 | 8.2.33-1~deb12u1 | DLA-4732-1 |
| trixie | php8.4 | 8.4.24-1~deb13u1 | DSA-6406-1 |
| sid / forky | php8.4 | 8.4.24-1 | — |
「NVD が 8.2 以降と書いているから 7.4 は関係ない」とは言えない。サポート切れの系列を独自ビルドで動かしているなら、php_pgsql_convert() の該当箇所が自分のビルドに含まれるかを確認する必要がある。
CVE-2026-17544: 8.4.3RC1 で入った回帰
こちらは対照的に、範囲がはっきりしている。
bccomp() は2つの数値文字列を比較する BCMath の関数である。内部では文字列を数値表現に変換する bc_str2num() を通る。アドバイザリによれば、scale による切り詰めで生じた末尾のゼロがさらに取り除かれる経路で、バッファは短く確保し直されるのに、コピー先として使うポインタが更新されない。結果として確保した領域の外へ書き込む。
破壊されるのはバッファの確保場所に応じてスタックとヒープの両方に及ぶ、とアドバイザリは書いている。
重要なのは Debian トラッカーが記録している2つのコミットである。
- 混入:
063c3c852236ecbe45ab23c0fb271b6292ce82c3(php-8.4.3RC1) - 修正:
fa18dab73f9340448c0d5c0a1d75d3fec844b358(php-8.4.24)
8.4.3RC1 で入ったコードなので、8.2 系・8.3 系には存在しない。 Debian も php8.2 と php7.4 を「脆弱なコードが存在しない(Vulnerable code not present)」として not-affected と判定している。
ここで読み違えやすいのは、トラッカーの not-affected を「まだ対応していない」と受け取ってしまうことだ。これは未対応ではなく、該当コードが無いという積極的な判定である。
そして ext-bcmath は既定で有効な拡張ではない。ただし、金額計算や大きな整数を扱うライブラリが composer.json で ext-bcmath を要求していることは珍しくないので、「自分では使っていない」は根拠にならない。php -m の実測で見る。
実際に試す: 判定をスクリプトに落とす
ここまでの条件を整理すると、判定は次の3つの掛け合わせになる。
- PHP のバージョン(系列ごとに修正版が違う)
- 拡張が読み込まれているか(
pgsql/bcmath) - 該当関数を実際に呼んでいるか
これを1本の POSIX シェルスクリプトにする。php が PATH にあれば自動で読み、無い環境(あるいは資産台帳の値で机上判定したいとき)は PHP_VERSION / PHP_MODULES を環境変数で渡せるようにしてある。
1 | |
動かした結果
検証用に、両方の関数を使う PHP ファイルを1つ置いた。
1 | |
4つの環境を想定して回した実際の出力である。
1 | |
3つ目のケースが、この記事で言いたかったことをそのまま出している。同じ PHP 8.3.32 という1つの事実から、2件の CVE について別々の理由で「影響なし」が出る。片方は拡張を読み込んでいないから、もう片方は該当コードがそのバージョンに存在しないからである。
4つ目も同様で、8.2 系は 17543 だけが該当し、17544 は無関係になる。「PHP を 8.4.24 に上げれば両方直る」は結論としては正しいが、上げられない事情があるときに、どちらが本当に効いているのかを分けて考えられるかどうかで対応の急ぎ方が変わる。
判定を止めないための注意
スクリプトは補助であって、次の点は人が見る必要がある。
grepはコメントアウトされた行も文字列中の一致も拾う。呼び出し箇所が出たら、実際に外部入力が引数へ届くのかを目で追う。php -mはコマンドライン(CLI)の SAPI が読み込んでいるモジュールを出す。FPM や mod_php とはphp.iniが別のことがあるので、Web 側の実効値はphpinfo()あるいはphp-fpm -iで確認する。- ディストリのパッケージは上流のバージョン番号と一致しない。Debian の
8.2.33-1~deb12u1のように、修正がバックポートされた版は上流版と番号がずれる。上流版だけで判定するとバックポート済みの環境を誤って「影響あり」にする。
3つ目は特に扱いを間違えやすい。スクリプトが見ているのは php -r 'echo PHP_VERSION;' の値なので、Debian のバックポート版では上流の 8.2.33 相当が入っていても 8.2.32 と表示されることがある。ディストリのパッケージで運用しているなら、判定の根拠はディストリのトラッカーとパッケージ版数のほうに置くこと。スクリプトは「上流版で見た場合の目安」として使う。
まとめ
- CVE-2026-17543 は ext-pgsql の
pg_insert()/pg_update()/pg_select()/pg_delete()に限られる SQL インジェクション。エスケープ関数とE'...'形式の前提の食い違いが原因で、8.2 系まで遡る。Debian は 7.4 系にも修正を入れている - CVE-2026-17544 は ext-bcmath の
bccomp()の領域外書き込み。8.4.3RC1 で入った回帰なので 8.2 系・8.3 系は対象外 - どちらも NVD の Primary は CVSS 3.1 で 9.8 Critical、CNA の PHP は CVSS 4.0 で 8.1 High。数字を引くときは物差しを明記する
- 判定は「バージョン × 拡張の有無 × 呼び出しの有無」の掛け合わせ。掛け合わせのぶんだけ、バージョン一覧を眺めるだけでは結論が出ない
2件の対応状況は 脆弱性対応ウォッチ にまとめてある。AWS / GCP / Azure / Linux それぞれの対応の入口と、Debian の各リリースでの修正版を一覧にしてあるので、資産の置き場所から逆に引きたいときはそちらを見てほしい。