この記事ではセキュリティ速報に特化して解説します。サプライチェーン全体のリスクと対策は サプライチェーンセキュリティ2026|攻撃手法・防御ツール・実践チェックリスト をご覧ください。

何が起きたか — 結論ファースト

CVE-2026-6722 — PHP SOAP拡張のRCE脆弱性(CVSS 9.5 Critical)

  • 何が起きた: PHPのSOAP拡張(ext-soap)にUse-After-Free脆弱性。条件が揃うとリモートから任意コード実行(RCE)に至る可能性がある。
  • 影響対象: PHP 8.2〜8.5系でSOAP拡張が有効な環境。php -m | grep soap に出力があれば対象。
  • 対応: 修正版(8.2.31 / 8.3.31 / 8.4.21 / 8.5.6)にアップデート。
  • SOAP非使用なら影響なし: REST/GraphQL のみのアプリは対象外。

CVE-2026-6722 はPHPのSOAP拡張(ext-soap)に存在するUse-After-Free脆弱性で、Apache Mapノード内の重複キー処理に起因する。SOAP拡張が有効化された環境で攻撃者がSOAPリクエスト本文を制御できれば、解放済みオブジェクトへの参照を介してメモリ破壊が発生し、認証不要・ユーザー操作不要のリモートコード実行(RCE)に発展する可能性がある。

ただし、本脆弱性の影響を受けるのは ext-soap が有効かつ実際にSOAP通信を行っている環境に限定される。現代的なWebアプリケーションの大多数はREST APIやGraphQLで構築されており、SOAPは主にB2Bシステム連携・決済ゲートウェイ・ERP/SAPとのバックエンド統合など、エンタープライズ向けレガシー連携に残存している技術だ。一般的なWordPress・Laravel・SymfonyブログやeコマースサイトがSOAPを直接使うケースは少数であり、まず自環境での ext-soap の有無を確認することが第一歩となる。

公式アドバイザリ(GHSA-85c2-q967-79q5)は2026年5月7日に公開され、修正版 PHP 8.2.31 / 8.3.31 / 8.4.21 / 8.5.6 が同日に同時リリースされた。報告者は brettgervasoni、修正担当はPHPコアコミッタの Ilija Tovilo(iluuu1994)、レビューは Niels Dossche(ndossche)である。

php/php-src repository

CVSS 9.5 Patched CVE-2026-6722 No auth required

あなたは影響を受けるか — 30秒判定

flowchart TD A["PHPを運用?"] --> B{"バージョンは?"} B -->|8.2.x < 8.2.31| C{"ext-soap 有効?"} B -->|8.3.x < 8.3.31| C B -->|8.4.x < 8.4.21| C B -->|8.5.x < 8.5.6| C B -->|パッチ版以上| Z["✅ 影響なし"] C -->|有効 + SOAP受信| R["⚠ 対応が必要
パッチ版へアップグレード"] C -->|有効だが内部利用のみ| Y["経路確認 + アップグレード推奨
SoapClient呼び出しを棚卸し"] C -->|無効| W["✅ 本CVEの影響なし
通常のパッチサイクルで更新"] R --> D["WAF / IDS で
SOAPトラフィック異常を監視"]

CVE-2026-6722の正体 — SOAP拡張のUse-After-Free

ext-soapとApache Map拡張要素

PHPのSOAP拡張は、SOAP 1.1/1.2に加えてApacheが導入した非標準拡張要素である apache:Mapをパースする実装を持つ。apache:Map はキー・バリュー対をXMLで表現する型で、ext-soapはこれをパースしてPHPの連想配列に変換する。

このマップ要素の処理過程で、XMLの id 属性と href 属性を使ったオブジェクト共有(deduplication)が行われる。SOAPメッセージ内では同じオブジェクトを複数箇所で参照するために、

  • ・<element id="o1">...</element> — 実体を1か所で定義する。
  • ・<element href="#o1"/> — 別の場所から href で参照する。

という形式が使える。ext-soapはこの「同じ参照は同じPHPオブジェクトに解決する」ためのテーブルとして SOAP_GLOBAL(ref_map) というグローバルハッシュマップを使う。

脆弱性の本質 — 参照カウント未更新

soap_add_xml_ref() は新しく作ったPHPオブジェクトを ref_map に登録するが、ここでZ_ADDREF(参照カウントのインクリメント)を呼んでいなかった。SOAPメッセージのライフサイクル内では通常はそれでも問題ないが、apache:Map に重複キーが含まれているとPHP連想配列の挙動として「同じキーへの2回目の代入で1回目のバリューが破棄」され、参照カウントが正しく管理されていない元のオブジェクトが解放される。

しかし ref_map 側はその解放を知らない。結果として ref_map には解放済みオブジェクトを指すダングリングポインタが残る。続けて href 参照が同じIDを引いた瞬間、ref_map から解放済みポインタが取り出され、結果オブジェクトにコピーされる。これが典型的なUse-After-Freeである。

// php-src/ext/soap/php_encoding.c(脆弱版イメージ)
static void soap_add_xml_ref(zval *data, xmlNodePtr node)
{
    // ref_map[node] = data  ← Z_ADDREF が抜けている
    zend_hash_index_update(SOAP_GLOBAL(ref_map), (zend_ulong)node, data);
    // Apache Map で同じキーに上書きされると、
    // ここに登録された data が free されるが
    // ref_map 側の参照は残り続けてしまう
}

修正コミットの要点

公開された修正は概念的に次の2点だ。

  1. ref_map に登録する前に Z_ADDREF_P() を呼び、参照カウントを増やしてから保存する。
  2. マップのデストラクタとして zval_ptr_dtor を設定し、エントリ上書き時に正しく参照カウントが減らされ、ゼロになったら本当のメモリ解放に進むようにする。
// 修正後の概念コード
static void soap_add_xml_ref(zval *data, xmlNodePtr node)
{
    Z_TRY_ADDREF_P(data);  // ← 追加: 参照カウントを増やしてから保存
    zend_hash_index_update(SOAP_GLOBAL(ref_map), (zend_ulong)node, data);
}

// ref_map 初期化時にデストラクタを設定(概念)
zend_hash_init(SOAP_GLOBAL(ref_map), 0, NULL, ZVAL_PTR_DTOR, 0);

Use-After-Free脆弱性として典型的だが、SOAP拡張という「枯れた」と思われがちなコードに10年以上潜伏していた点が、PHPコアの監査の難しさを物語る。同様の発見はAxios CVE-2026-40175でも見られ、長期保守プロジェクトの古い経路ほどリスクが高い。なお関連する別経路の脆弱性として CVE-2026-7261(同じくUse-After-Free)や CVE-2026-7262(NULLポインタ参照)も同時期のPHPアドバイザリで議論されており、今回の修正バージョンは SOAP まわりの周辺修正を含めて押さえておきたい。

影響範囲とあなたの30秒判定

影響を受けるワークロード

SOAPは2000年代に策定されたXMLベースのRPCプロトコルで、現代のWebアプリケーション開発では REST や GraphQL に置き換えが進んでいる。本脆弱性の影響を受けるのは、ext-soapが有効化された状態でSOAP通信を行っている環境に限られる。

  • ・SAP/Salesforce/NetSuite 連携バッチ — エンタープライズ系の連携APIではSOAP/XMLが依然として使われているケースがある。
  • ・決済ゲートウェイの旧API — 古い決済サービスの一部はSOAPベースのAPIを提供している。
  • ・社内向けレガシーシステム連携 — RESTへの移行前にSOAPエンドポイントを残しているケース。
  • ・PHPベースのESB/統合ミドルウェア — 複数システムを繋ぐ統合層でext-soapを使用している場合。

一般的なWordPressブログ・Laravelアプリ・SPA + REST APIの構成は影響を受けない。

Webサーバ/PHP-FPM運用での影響

PHP-FPM配下で動くWebアプリでも、SoapServer クラスを使ったエンドポイント、もしくは SoapClient で外部からのレスポンスを処理しているコードがある場合は対象となる。念のために自プロジェクトの依存ツリーを確認しておくとよい。

# 自プロジェクトでSOAP拡張への依存があるかを素早く調べる
grep -RIn --include='*.php' -E 'SoapClient|SoapServer|new \\?Soap' .
composer show -t 2>/dev/null | grep -i soap

検出した呼び出し経路が「定数の宛先しか叩かない」「TLS+認証必須の閉域だけ」「攻撃者が本文を制御できない」のいずれかなら、悪用条件は満たしにくい。逆に「未認証のWebhook/SAMLレスポンス/外部公開SOAP」のいずれかに該当するなら、対応の優先度を上げるとよい。

主要SOAPライブラリとext-soapの関係

PHPのSOAPエコシステムで広く使われているライブラリの多くは、内部的にext-soapに依存している。そのため「自分でSOAPを書いていないが、ライブラリ経由でSOAPを使っている」環境も本CVEの影響範囲に含まれる点に注意したい。

ライブラリ ext-soap依存 備考
phpro/soap-client ✅ あり ext-soapをラップした型安全クライアント。Composerで広く採用
php-soap/ext-soap-engine ✅ あり ext-soapをエンジンとして使うアダプタ層。WSDLパースもext-soap経由
laminas/laminas-soap ✅ あり Laminas(旧Zend Framework)のSOAPコンポーネント
NuSOAP ❌ なし 純PHP実装のためext-soap非依存。ただし2016年以降メンテ停止で別のリスクあり

これらのライブラリを使っている場合、SoapClientSoapServer を直接書いていなくてもext-soapが有効化されている可能性がある。Composerで依存関係を確認するには次のコマンドが手早い。

# インストール済みパッケージにSOAP関連があるか確認
composer show | grep -i soap

# 依存ツリーで誰がSOAPを引き込んでいるか確認
composer depends ext-soap 2>/dev/null || echo "ext-soapへの明示的依存なし"

# PHPがext-soapをロードしているか最終確認
php -m | grep -i soap

composer depends ext-soap に出力がある場合、そのパッケージがext-soapを前提としている。NuSOAPを使っている場合はext-soap非依存なので本CVEは影響しないが、メンテが終了していることによる別の脆弱性リスクについて別途検討することを勧める。

CVSSベクターの読み方

CVSS 4.0スコア9.5(Critical)の内訳は次のとおりだ。

  • ・AV:N(Network) — リモートから攻撃可能。ローカルアクセス不要。
  • ・AC:H(High) — 攻撃複雑度は高い。Use-After-Freeの安定エクスプロイトには内部構造の知識が必要。
  • ・AT:P(Present) — 一定の前提条件が必要(=SOAP拡張有効、SOAPリクエストを受理する経路)。
  • ・PR:N(None) — 認証不要。
  • ・UI:N(None) — ユーザー操作不要。
  • ・VC:H/VI:H/VA:H — 機密性・完全性・可用性すべて高インパクト。

AC:Hは「安定したエクスプロイトの実装は容易ではない」ことを示す。理論上はRCEに至る経路が存在するが、信頼性の高いPoCの作成にはヒープ整形の精度が求められる。現時点(2026年5月)では公開されたPoCは確認されていない。SOAP環境を運用している場合は通常のパッチサイクルより優先して更新することが望ましいが、ext-soapを使っていない環境は通常のタイミングで問題ない。

パッチ適用と確認 — 対策手順

ここからが本題の「対策と確認」だ。まず Step 1 でSOAP拡張の有無を確認し、使っていない場合は対応不要と判断できる。

Step 1 — 影響有無の確認

まず、自分のPHPバージョンとSOAP拡張の有無を確認する。php -m | grep soap に出力がなければ本CVEの影響は受けない。

# PHPバージョン(CLIとFPMで異なる場合がある)
php -v
php-fpm -v 2>/dev/null || /usr/sbin/php-fpm -v

# SOAP拡張の有無
php -m | grep -i soap
php --ri soap 2>/dev/null | head -5

# Apache mod_phpの場合(バージョン確認)
apachectl -M 2>/dev/null | grep -i php

出力例で php -vPHP 8.3.30PHP 8.2.30PHP 8.4.20PHP 8.5.5 以下、かつ php -m | grep soap がヒットしていれば影響対象である。Dockerコンテナ運用ならイメージタグも併せて確認する。

# Dockerコンテナの一括チェック例
for c in $(docker ps --format ''); do
  echo "=== $c ==="
  docker exec "$c" php -v 2>/dev/null | head -1
  docker exec "$c" php -m 2>/dev/null | grep -i soap
done

Step 2 — パッチ適用(環境別)

主要環境のアップグレード手順を並べる。aptyumbrew/Docker/Composer ベースまで、自環境に該当するものを選んで実行する。

# Debian / Ubuntu(Sury PPA 利用ケースが多い)
sudo apt update
sudo apt list --upgradable | grep -i php
sudo apt install --only-upgrade 'php8.*' 'php8.*-soap' -y
sudo systemctl restart php8.4-fpm  # 該当バージョンに合わせて
sudo systemctl restart apache2 || sudo systemctl restart nginx
# RHEL / Rocky / AlmaLinux(Remi リポジトリ)
sudo dnf upgrade --refresh 'php*' -y
sudo systemctl restart php-fpm
sudo systemctl restart httpd || sudo systemctl restart nginx
# macOS(開発機)
brew update && brew upgrade php
brew services restart php

# Docker(公式php イメージ)
docker pull php:8.4-fpm
# Dockerfile の FROM を php:8.4.21-fpm 以上に固定
# docker compose pull && docker compose up -d

CMS同梱の独自PHPやマネージドホスティングを使っている場合は、コントロールパネルから「PHPバージョン切替」で 8.2.31/8.3.31/8.4.21/8.5.6 系を選ぶ。コンテナイメージ・ベースイメージのキャッシュが効いていて古いPHPのままになるケースが頻発するため、docker pull を明示的に実行する点だけ忘れずに。

Step 3 — 適用後の検証

アップグレード後は、バージョンと起動状態の両方を確認する。

php -v                         # 8.2.31 / 8.3.31 / 8.4.21 / 8.5.6 以上を確認
php-fpm -tt 2>&1 | tail -10    # 設定リロード可否
systemctl status php8.4-fpm    # 起動状態
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/healthz

WordPress/Laravel/Symfony等のアプリケーションは、起動後に管理画面・主要ページ・SOAP連携バッチを一通り疎通させ、回帰がないか確認する。SoapClientがWSDLキャッシュ(/tmp/wsdl-*)を使っている場合、まれに古いキャッシュとの整合性問題が発生するため、必要に応じて削除する。

sudo rm -f /tmp/wsdl-* /var/cache/php-wsdl-* 2>/dev/null
sudo systemctl reload php-fpm

Step 4 — 即時アップグレードできない場合の暫定対策

検証期間や本番リリースゲートでパッチ適用が即できない場合の「橋渡し対策」を順に挙げる。

  • ・ext-soapを一時的に無効化php.iniextension=soap をコメントアウト、または /etc/php/8.4/cli/conf.d/20-soap.ini をリネーム。
  • ・公開SOAPエンドポイントをWAFでブロック:URLパス・Content-Type: application/soap+xmlSOAPAction ヘッダのいずれかで遮断。
  • ・SoapClientの宛先を許可リスト化:信頼できる固定ホストのみへ。任意URL受付経路は止める。
  • ・XML外部実体(XXE)対策を含めて見直すlibxml_disable_entity_loader(true) 系の運用ポリシーも合わせて点検。

Step 5 — 侵害有無のチェック(IoC観察ポイント)

CVE-2026-6722固有の確定的IoCはアドバイザリ公開時点では限定的だが、Use-After-Free→RCEの典型的痕跡として次を観察する。

  • ・php-fpm/apache2 のSIGSEGV/core dump発生/var/log/syslogjournalctl -u php8.4-fpm | grep -i 'segfault\|sigsegv'
  • ・SOAP系エンドポイントへの異常リクエストapache:Map を多用、巨大な href 連鎖、同一IDの繰り返し。
  • ・ext-soap利用プロセスから派生する想定外の子プロセスauditd の execve ログで php -rsh -ccurl|sh パターンを監視。
  • ・SetUID/ホームディレクトリ配下に新規バイナリ:Webshell設置の典型痕跡。
# 直近30日のセグフォルト・OOM・異常終了を抽出
journalctl --since "-30 days" -u php8.4-fpm \
  | grep -Ei 'segfault|sigsegv|killed|core' | tail -50

# auditd でphp配下からの execve を監視(事前にルール仕込みが必要)
auditctl -a always,exit -F arch=b64 -S execve -F auid!=4294967295 -k php-exec

RCEに発展するシナリオと攻撃面

Use-After-FreeがRCEに化ける仕組み

ref_map から取り出されたダングリングポインタは、解放済みヒープ領域を指している。攻撃者が同一リクエスト内でその領域に新しい割り当てを行えれば、攻撃者制御のバイト列がそのポインタの先に再構築される。PHPのオブジェクトヘッダ zend_object には zend_object_handlers *handlers へのポインタが含まれ、メソッド呼び出し時はここを経由してC関数ポインタテーブルに飛ぶ。

つまり、

  1. SOAPリクエストでオブジェクトA(解放されるもの)を作る。
  2. Apache Map重複キーでオブジェクトAが解放される。
  3. 同じSOAPリクエストで、AのあったヒープスロットにオブジェクトBを再確保(攻撃者制御の文字列・配列で精密に「ヒープ整形」)。
  4. href 経由でAだったポインタを参照すると、Bの内容を「オブジェクトA」として扱う。
  5. Bの中の handlers ポインタをROPガジェットの先頭や攻撃者の用意したテーブルに指すよう仕込むと、メソッド呼び出しで任意関数へジャンプ。

この経路はPHPコアエクスプロイトでは定番で、CVE-2024-xxxx/2025-xxxx 系のObject型UAFでも繰り返し見られている。「Use-After-Free単独ではDoSにしかならない」という時代は終わっている

サプライチェーン経由の波及リスク

PHPコア自体の脆弱性は、サプライチェーン上での波及が極めて大きい。Composer経由でインストールされたパッケージが内部でSOAPを叩いているかどうかは、利用者からは見えにくい。CVE-2026-40175(Axios)や CVE-2026-40261(Composer)と同様、「自分のコードは安全だが、依存先が呼ぶ」典型例である。SBOM/依存ツリーを可視化していなければ、影響範囲の特定すら時間がかかる。

エコシステム全体の対策論は サプライチェーンセキュリティ2026|攻撃手法・防御ツール・実践チェックリストAxios CVE-2026-40175|CVSS 9.9のSSRF+RCE で整理しているため、運用責任者は今回のCVE対応と併せて目を通しておきたい。

攻撃面の最小化

恒久的な対策として、攻撃面(attack surface)の縮減も並走させる。

  • ・SOAP公開エンドポイントの棚卸し:本当に必要なホストにだけ閉じ込める。
  • ・SoapClientの宛先固定:環境変数・configで固定URL/許可ホストリスト管理。
  • ・XML処理全般のハードニング:DTD無効化、外部実体ロード無効化、XML爆弾耐性。
  • ・PHP-FPMのリソース制限pm.max_childrenrequest_terminate_timeout を厳格化し、暴走プロセスの影響を限定。
  • ・コンテナ最小権限USER を非rootに、cap_drop: ALL を基本に、書き込み可能パスを最小化。

過去のPHP系CVEとの比較・教訓

PHPコアレベルのCVEは数年ぶりに「9.5級」の重大度で出てきた。直近の代表例と並べて、本件の重さを見ておく。

CVE 概要 種別 認証要否 修正バージョン
CVE-2026-6722 (本件) ext-soap Apache Map で Use-After-Free → RCE UAF / メモリ破壊 不要 8.5.6 / 8.4.21 / 8.3.31 / 8.2.31
CVE-2024-1874 proc_open の引数注入 コマンドインジェクション 不要 8.2.17 / 8.3.5
CVE-2024-2756 HTTPクッキーの不正パース 認証バイパス 不要 8.2.18 / 8.3.6
CVE-2024-4577 CGI引数注入(Argument Injection) RCE 不要 8.1.29 / 8.2.20 / 8.3.8
CVE-2025-0001 OPcache周りのメモリ破壊(概念例) UAF 不要 8.3.x 系列

今回のCVEは CVE-2024-4577(CGI引数注入)と同じ「リモート・認証不要」という属性を持つ。違いは、4577がCGI構成に依存したのに対し、今回はSOAP拡張の有無に依存する点だ。CGIは多くの環境で有効化されているが、SOAPは特定のユースケースに限られるため、実際の影響範囲はCVSSスコアが示す「Critical」より絞られる。

開発者・運用者への教訓

1. 「枯れた」拡張ほど監査の谷間に落ちる

ext-soapは10年以上前からPHPに同梱されている。枯れた=安全ではなく、枯れた=最近の監査の優先度が下がっている場合がある。プロトコルスタックの古いコードに対しては、Coverity/oss-fuzz/CodeQLによる継続的なファジングを意図的に投資する価値がある。

2. 「使っていないつもり」の拡張を可視化する

php -mphp --ini の出力を構成管理(Ansible・Chef・SaltStack)の証跡として固定化しておくと、CVE出現時に「該当/非該当」を即決できる。

# IaC化用のスナップショット例(CIで定期実行)
php -m | sort > /var/log/php/loaded_extensions.txt
php --ini | tee /var/log/php/ini_files.txt
sha256sum /var/log/php/loaded_extensions.txt /var/log/php/ini_files.txt

3. SOAP/XML処理は専用WAFルールで保護する

ModSecurity/Coraza等のWAFには、SOAPボディの構造異常(深いネスト・巨大なid/href・再帰参照)を検出するルールセットが存在する。「アプリ側のXMLパーサの脆弱性」は今後も繰り返される前提で、入口側の防御を二重化する。

4. PoC公開前後の温度差を組織内ルールに

CVSS 9.5級は「PoC公開前=AC:Hで安心」「PoC公開後=スキャナの餌食」の温度差が極端だ。組織のセキュリティ対応SLAを「Critical CVE公開から24時間以内に影響有無確認、72時間以内にパッチ適用または明確な暫定対策」のように明文化しておく。

関連トピック

本件はPHPエコシステム単独の問題に見えるが、「サプライチェーン上のメモリ安全性」「Webサーバ系ミドルウェアのプロトコル実装」という構造課題の延長線上にある。同時期に出た以下のCVEと併読すると、運用判断が補強される。

参照ソース


本記事について 本記事は公式アドバイザリ(GHSA-85c2-q967-79q5)および PHP 8 ChangeLog をもとに執筆した速報です。CVSSスコア・修正版情報は公式アドバイザリの更新に追随します。SOAPを利用している環境の担当者は影響確認と必要に応じたアップグレードを検討してください。


この記事はAI業界の最新動向を速報でお届けする「AI Heartland ニュース」です。