2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WordPress 4.7〜7.1.1に未認証の不正読込 CVE-2026-87902──7.1.2更新と攻撃痕跡の確認

2
Posted at

WordPressで企業サイト・ブログを運用しているWeb担当者、制作会社の保守担当者向けの記事です。
2026年9月22日、WordPress本体(コア)の脆弱性 CVE-2026-87902 を修正したセキュリティリリース 7.1.2 が公開されました。ログイン不要で、条件がそろうとリモートからのコード実行(RCE)につながります。修正公開の当日から攻撃が観測されています。
この記事では「自分のサイトは更新済みか」「RCEの前提条件がそろっているか」「すでに踏まれていないか」を、コピペで確認できるコマンド付きでまとめます。

何が起きたのか

項目 内容
CVE CVE-2026-87902(GitHub Advisory: GHSA-7hp8-65ch-5whp)
種別 パストラバーサルによるローカルPHPファイルの読み込み(CWE-98:include/require に渡すファイル名の制御不備)
認証 不要(ユーザー操作も不要)
影響バージョン 4.7.0 〜 7.1.1(約9年分)
修正版 7.1.2 ほか、4.7 系までの全ブランチにバックポート
深刻度 CVSS v4.0 9.2(Critical)
悪用状況 2026-09-25 に米CISAが KEV(悪用が確認された脆弱性カタログ) へ追加

公式発表(WordPress 7.1.2 Release)によると、未認証の攻撃者が条件次第で、固定ページのテンプレートを決める処理(get_page_template())に、有効化中テーマの外にある読み取り可能なPHPファイルを読み込ませられる、という問題です。URL から組み立てたテンプレート名に ../(上の階層へ戻る指定)のチェックが漏れていたことが原因とされています。

ポイントは3つです。

  1. 対象がほぼすべての現役サイト。 プラグインではなく本体の脆弱性なので、「プラグインは最小限にしている」サイトも対象です。
  2. RCEまで行くには前提条件がある。 ただし「該当しないはず」と判断するより、更新するほうが早く確実です。条件の確認は後述します。
  3. 修正と同時に技術的な詳細が公開され、攻撃が即座に始まった。 国内でもレンタルサーバー各社が注意喚起や強制アップデートを実施しています。自動更新が効いていない・止めているサイトは、今も未修正のまま残っている可能性があります。

攻撃の成立条件は確認に必要な範囲にとどめ、再現手順は扱いません。以下は「同じ被害を防ぐ」ための確認と対処です。

1. まずバージョンを確認する(1分)

WP-CLI が使える環境ならこれが最速です。

# 現在のコアバージョン
wp core version

# 同じブランチ内の更新(マイナー更新)があるか
wp core check-update --minor

管理画面なら「ダッシュボード → 更新」で確認できます。WP-CLI が無い環境では、コアに同梱されているバージョン定義ファイルを直接見ます。

# WordPress のドキュメントルートで実行
grep "wp_version =" wp-includes/version.php

修正版の早見表

自分のブランチの番号以上になっていれば修正済みです(GitHub Advisory 記載の修正版)。

ブランチ 修正版 ブランチ 修正版
7.1 7.1.2 5.9 5.9.18
7.0 7.0.6 5.8 5.8.17
6.9 6.9.9 5.7 5.7.19
6.8 6.8.10 5.6 5.6.21
6.7 6.7.9 5.5 5.5.22
6.6 6.6.9 5.4 5.4.23
6.5 6.5.12 5.3 5.3.25
6.4 6.4.12 5.2 5.2.28
6.3 6.3.12 5.1 5.1.26
6.2 6.2.13 5.0 5.0.29
6.1 6.1.14 4.9 4.9.33
6.0 6.0.16 4.8 4.8.32
4.7 4.7.37

古いブランチにも修正は届いていますが、公式に「積極的にサポートしているのは最新版のみ」とされています。今回をきっかけに、最新の 7.1 系へ上げる計画も立てておくのが安全です。

複数サイトをまとめて棚卸しする

保守契約で複数サイトを抱えている場合は、サーバー上の WordPress を一括で洗い出します。

# /var/www 配下の WordPress を探し、バージョンを一覧表示
find /var/www -name version.php -path '*/wp-includes/*' 2>/dev/null | while read -r f; do
  printf '%s\t%s\n' "$(grep -oP "wp_version = '\K[^']+" "$f")" "${f%/wp-includes/version.php}"
done | sort -V

2. 対処:更新する

更新前にバックアップを取ります。

# DBとファイルのバックアップ(保存先は公開ディレクトリの外へ)
wp db export ~/backup-db-$(date +%Y%m%d).sql
tar czf ~/backup-files-$(date +%Y%m%d).tar.gz wp-content wp-config.php

同じブランチ内の修正版へ上げるだけなら、互換性への影響は小さいはずです。

# 同じブランチの最新修正版へ(例: 6.8.x → 6.8.10)
wp core update --minor

# DB の更新が必要な場合に備えて実行
wp core update-db

# 反映確認
wp core version
wp core verify-checksums

最新の 7.1.2 まで上げる場合は wp core update を使います。メジャー更新はテーマ・プラグインとの互換性に影響するため、ステージング環境で先に確認してから本番に当ててください。

自動更新が止まっていないか確認する

今回のようなセキュリティリリースは、通常はマイナー更新として自動で適用されます。それでも未修正のサイトが残る典型は、自動更新を設定で止めているケースです。

# wp-config.php で自動更新を止めていないか
grep -nE "AUTOMATIC_UPDATER_DISABLED|WP_AUTO_UPDATE_CORE|DISALLOW_FILE_MODS" wp-config.php

# テーマ・プラグインのフィルタでコア更新を止めていないか
grep -rnE "auto_update_core|automatic_updater_disabled|allow_minor_auto_core_updates" \
  wp-content/themes wp-content/plugins wp-content/mu-plugins 2>/dev/null

AUTOMATIC_UPDATER_DISABLED が true、または WP_AUTO_UPDATE_CORE が false になっていれば、マイナー更新も止まっています。運用上の理由が無ければ、少なくともマイナー更新(セキュリティ修正)は自動で入る設定に戻します。

// wp-config.php:マイナー更新(セキュリティリリース)は自動適用する
define( 'WP_AUTO_UPDATE_CORE', 'minor' );

3. RCEの前提条件がそろっているか確認する

更新が済めば脆弱性そのものは塞がります。ここは「更新までの間に、自分のサイトがどれだけ危険だったか」を見積もり、次の節の痕跡調査をどこまで深くやるか決めるための確認です。

公式アドバイザリが示す前提条件は次の2つです。

  1. 有効化中のテーマ(親テーマ・子テーマ)の直下に、名前が page- で始まるディレクトリがある(例:page-templates)。Twenty Twelve / Twenty Fourteen や、Neve / Hestia / Sydney などが該当すると報じられています。
  2. サーバー上に、読み込まれると悪用の踏み台になる PHP ファイルがある。 代表例が PHP の付属ツール PEAR の pearcmd.php で、PHP の register_argc_argv 設定が On の環境では RCE につながるとされています。

テーマのディレクトリを見る

# 有効化中のテーマ(子テーマを使っている場合は親テーマも確認する)
wp theme list --status=active --fields=name,version
wp option get template     # 親テーマ
wp option get stylesheet   # 子テーマ(親と同じなら子テーマなし)

# テーマ直下に page- で始まるディレクトリがあるか
for t in "$(wp option get template)" "$(wp option get stylesheet)"; do
  find "wp-content/themes/$t" -maxdepth 1 -type d -name 'page-*'
done

PHP の設定と PEAR を見る

register_argc_argv は CLI とWeb(PHP-FPM / mod_php)で値が違うことがあるため、Web 側の設定を確認します。

# PHP-FPM の場合(バージョン部分は環境に合わせる)
php-fpm8.3 -i 2>/dev/null | grep -i register_argc_argv

# 読み込まれている php.ini の場所
php-fpm8.3 -i 2>/dev/null | grep -i "Loaded Configuration File"

# サーバー上の pearcmd.php の有無
find / -name pearcmd.php -not -path '/proc/*' 2>/dev/null

php.ini を置かずに PHP の組み込み既定値で動いている環境(公式 Docker イメージをそのまま使っている場合など)では、register_argc_argv が On になっていることがあります。

4. すぐに更新できないときの一時的な緩和

検証待ちなどで即時更新できない場合の選択肢です。いずれも制限を強める方向の設定で、更新の代替にはなりません。できるだけ早く 2. の更新を実施してください。

PHP:register_argc_argv を Off にする

Web 経由のリクエストで register_argc_argv を使う WordPress サイトは通常ありません。RCE への経路を狭めるため Off にします。

; php.ini(PHP-FPM / mod_php が読み込むもの)
register_argc_argv = Off
# 設定後に PHP-FPM を再読み込み(サービス名は環境に合わせる)
sudo systemctl reload php8.3-fpm

使っていない PEAR を導入している場合は、パッケージ管理ツールから削除するのも有効です(他のアプリが PEAR を使っていないことを確認してから)。

Web サーバー:pagename に上位階層の指定が入ったリクエストを拒否する

国内外の解説では、固定ページを指定するクエリパラメータ pagename に、エンコードされた .. を含むアクセスが攻撃の典型として挙げられています。正規の固定ページ名に .. が入ることは無いため、拒否して困ることはまずありません。

nginx の場合(server ブロック内):

# pagename に ..(URLエンコード・二重エンコード含む)が入ったら 403
if ($arg_pagename ~* "(\.\.|%2e%2e|%252e%252e)") {
    return 403;
}

Apache の場合(.htaccess の WordPress のルールより前に置く):

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{QUERY_STRING} (^|&)pagename=[^&]*(\.\.|%2e%2e|%252e%252e) [NC]
RewriteRule ^ - [F]
</IfModule>

これは観測された典型パターンを止めるだけで、すべての経路を塞げる保証はありません。あくまで更新までのつなぎです。Cloudflare などの WAF を使っている場合は、ベンダーが CVE-2026-87902 向けのマネージドルールを出していないかも確認してください。

5. すでに踏まれていないかを確認する

RCE は、更新しても入られた後の痕跡は消えません。2026-09-22 以降に未修正だった期間がある場合は、次を確認します。

アクセスログ

# pagename に上位階層の指定が入ったアクセス(9/22 以降のログを対象に)
zgrep -iE "pagename=[^& ]*(\.\.|%2e%2e|%252e)" /var/log/nginx/access.log* \
  | awk '{print $1}' | sort | uniq -c | sort -rn | head -20

# PEAR を狙ったアクセス
zgrep -iE "pearcmd|config-create" /var/log/nginx/access.log* | head -50

Apache の場合はログのパスを /var/log/apache2/access.log*(RHEL 系は /var/log/httpd/access_log*)に読み替えてください。ヒットしてもレスポンスが 403 / 404 なら失敗した試行の可能性が高いですが、200 を返しているものは要精査です。

不審な PHP ファイル

報告では、攻撃者が一時ディレクトリなどに PHP ファイルを書き込む動きが観測されています。

# 一時ディレクトリに PHP ファイルが無いか(本来ほぼ存在しない)
find /tmp /var/tmp -type f -name '*.php' -printf '%TY-%Tm-%Td %TH:%TM %p\n' 2>/dev/null

# 9/22 以降に WordPress 配下で作成・変更された PHP ファイル
find . -type f -name '*.php' -newermt '2026-09-22' -printf '%TY-%Tm-%Td %TH:%TM %p\n' | sort

# uploads 配下の PHP ファイル(本来存在しないはず)
find wp-content/uploads -type f -name '*.php'

PHP-FPM でプライベート一時ディレクトリ(systemd の PrivateTmp)を使っている場合は、/tmp/systemd-private-* 配下も確認対象です。

コアの改ざん・アカウント・常駐

# コア・プラグインのファイル改ざん検査
wp core verify-checksums
wp plugin verify-checksums --all

# 身に覚えのない管理者アカウントが増えていないか
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered

# 不審な常駐(mu-plugins / スケジュール実行)
ls -la wp-content/mu-plugins/
wp cron event list

痕跡が見つかった場合は、ファイルを消して終わりにせず、侵害前のバックアップからの復元と、管理者パスワード・DB パスワード・wp-config.php の認証用キー(salt)の変更までをセットで行ってください。

まとめ

  • CVE-2026-87902 は WordPress 4.7.0〜7.1.1 のコアにある未認証の脆弱性で、CVSS v4.0 は 9.2。修正当日から攻撃が始まり、CISA の KEV にも追加済み
  • まず wp core version で確認し、自分のブランチの修正版(最新は 7.1.2)以上へ更新する
  • 自動更新を止めている設定(AUTOMATIC_UPDATER_DISABLED / WP_AUTO_UPDATE_CORE)が無いか点検し、セキュリティ修正は自動で入る状態に戻す
  • 更新までのつなぎとして register_argc_argv = Off と、pagename の上位階層指定の拒否が使える
  • 9/22 以降に未修正の期間があったサイトは、アクセスログ・一時ディレクトリの PHP ファイル・管理者アカウントを確認する

関連記事


本記事のような更新漏れ・設定の抜けは、Web サイトを 9 つの守りでまるごと守るサイトドックでまとめて対策できます → https://sitedock.jp

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?