WordPress のユーザー登録プラグイン User Profile Builder に、未認証で管理者を乗っ取れる脆弱性が見つかりました。CVE-2026-15826、CVSS 9.8、対象は 40,000 サイト。Wordfence が 8 月 14 日に公開しています。数字だけ見れば「またか」で終わる話でしたが、引っかかったのは修正版の変更履歴でした。
authentication bypass introduced in the latest update
前回のアップデートで作り込んだ、と書いてあります。だとすると、真面目にセキュリティ修正を当てた人ほど危ないバージョンを使っていることになる。本当にそんなことが起きるのか気になったので、公式配布の zip を 4 版ぶん Claude に読み比べてもらって、docker で未認証から管理者ログインまで再現しました。結論から書くと、原因は 2 日前に出たばかりの”セキュリティ修正”でした。検証はすべて 2026-08-16 時点のもので、実際に攻撃されているという報告は公開情報では見ていません。
先に、やることだけ。
- 3.16.5 より前なら、3.16.6 に上げる。塞がるのは 3.16.5 からですが、7/28 に別の修正が出ているので現行最新まで
- すぐ上げられないなら、「登録後に自動ログイン」を一時的にオフにする。この設定が ON のサイトだけで成立します。本体の「だれでも登録」を切るのは効きません
- 3.16.4 を使っていた期間があるなら、ユーザー一覧を見る。見覚えのない管理者が増えていないか
登録に失敗しただけで、管理者としてログインできた
環境は docker です。WP 7.0.2 と MySQL 8.0 に UPB 3.16.4 を入れて、「登録後に自動ログイン」を ON にし、登録フォームを 1 ページ公開しました。そこへ、60 文字を超える長いユーザー名で登録を送ります。WordPress のユーザー名には長さの上限があるので、本来なら弾かれる登録です。実際、wp user list で確認してもユーザーは 1 人も増えていません。
ところが画面には「アカウントを作成しました」と出ました。しかも返ってきた HTML の中に、自動ログイン用の URL が 1 本混ざっています。登録そのものは失敗しているのに、ログインできる URL だけが発行されている状態でした。
そこでその URL を、登録とはまったく無関係の、cookie が空のブラウザで開いてみます。すると wp-admin に入れました。しかも admin、最初に作った管理者としてです。ユーザー一覧まで開けて、権限は完全な管理者でした。

未認証の第三者が、登録に失敗しているのに、サイトの管理者になれる。CVSS 9.8 はこれか、と手が止まりました。
なお、再現に使った値やパラメータは書きません。隔離した docker の中の話ですが、そのまま外へ持ち出せる形では出しません。
エラーが数値になると、管理者の ID と同じ 1 になる
そこで、3.16.4 と 3.16.5 の公式 zip を並べて、Claude に diff を読ませました。返ってきたのは、登録後に自動ログインさせる関数の、たった数行の差でした。
// 3.16.4(脆弱)
$user_id = absint( $user_id );
if ( ! $user_id || is_wp_error( $user_id ) ) { // ここは絶対に true にならない
return $redirect_old;
}
WordPress の wp_insert_user() は、登録に失敗すると WP_Error というエラーオブジェクトを返します。3.16.4 はそれを受け取ったあと、エラーかどうかを確かめる前に absint()(数値に変換する関数)へ通していました。ここで引っかかったのは、PHP がオブジェクトを整数に変換したら何になるのか、という点です。手元の PHP 8.2 で単体で確かめました。
absint( WP_Error のオブジェクト ) → int(1)
1 が返ります。そして WordPress で最初に作られる管理者の user ID も 1 です。つまりエラーは、数値に変換された時点で管理者の ID と同じ値になります。直後の「これはエラーか」という is_wp_error() は、渡ってきた 1 を見て「エラーではない」と判定しますから、チェックは素通りです。あとは ID 1 の管理者として、自動ログイン URL を発行するだけでした。
では、なぜ「登録の失敗」が引き金になるのか。長すぎるユーザー名を WordPress コアが拒否して、まさにその WP_Error を返すからです。3.16.4 にはユーザー名の長さをサーバー側で確かめる処理が無く、入力欄の maxlength は見た目だけだ、というのが見解でした。だから、狙って失敗させられます。

3.16.5 の diff では、この「エラーか」の判定が absint() の前に戻っていました。あわせてサーバー側にも 60 文字の制限が足されています。同じ内容を 3.16.5 に送ってみたところ、今度は「長すぎます」で弾かれて、自動ログイン URL は出ませんでした。
影響を受けるのは自動ログインを ON にしたサイトだけ
ここは正確に書きます。この脆弱性が成立するのは、「登録後にユーザーを自動でログインさせる」設定を ON にしているサイトだけです。UPB を入れた直後の既定値を確認したところ、これはオフでした。ですから、40,000 が全部そのまま該当するわけではありません。
ただ、会員サイトや、登録してすぐ使わせたいコミュニティで、この設定を ON にするのはごく普通です。珍しい設定ではありません。
本体の「だれでも登録」を切っても止まらない
次に気になったのは、WordPress 本体の「だれでもユーザー登録ができるようにする」を切れば防げるのではないか、という点でした。定番のハードニングですし、僕もそう思いました。効きません。
そこで登録フォームまわりも読ませてみると、UPB は本体のその設定を見ていない、という答えが返ってきました。本体設定を読む代わりに true を固定で使う分岐があり、しかも「以前は本体設定を見ていた」という趣旨のコメントがそのまま残っているそうです。だから登録フォームを置いたページが公開されてさえいれば、本体側で登録を止めていても動きます。この 2 点、つまり自動ログインが条件であることと本体設定が効かないことは、どちらも advisory には書かれていなくて、読ませてみるまで気づけませんでした。
原因は、2 日前に出たセキュリティ修正だった
最初に引っかかった「前回のアップデートで作り込んだ」に戻ります。配布された版を時系列に並べると、こうなっていました。
| 日付(2026) | 版 | 内容 |
|---|---|---|
| 7/7 | 3.16.3 | セキュリティ強化 |
| 7/14 | 3.16.4 | 自動ログインのセキュリティ修正(CVE-2026-15368) |
| 7/16 | 3.16.5 | 本件の認証バイパス修正(CVE-2026-15826・CVSS 9.8) |
| 7/28 | 3.16.6 | 添付ファイルの所有権に関する修正 |
3.16.4 は、別の脆弱性(こちらも自動ログイン絡み)を塞ぐために出た”セキュリティ修正版”です。その修正で今回の関数にエラーチェックが足され、そのときに順番が入れ替わりました。3.16.5 の変更履歴にも、そう書かれています。
Fix: Security issue regarding authentication bypass introduced in the latest update
3.16.4 の寿命は 2 日でした。7 月の 3 週間だけで、セキュリティ修正が 4 版出ています。セキュリティ修正が次の脆弱性を作るのは、どのプラグインにも起こり得ることです。
早く当てた人だけが 3.16.4 に残っている
3.16.4 に今もいるのは、7/14 のセキュリティ修正をその 2 日のうちに当てて、それきり触っていない人です。次の版が出たのは、その 2 日後でした。つまり、素早く反応した人ほど、この版のまま止まっています。更新をサボった人が被害を受ける、といういつもの形になりません。
逆に、7 月をまるごと放置した人は、この版を使っていないので今回の脆弱性の影響を受けません。その代わり、この版が塞ぐはずだった別の脆弱性が残ったままです。最後に更新した日で、どちらが開いているかが決まります。
僕らの検査でも、この脆弱性は止まらない
僕らが作っている PatchOn は、更新を検証環境で試してから本番に当てるサービスです。ただ、この脆弱性は検査を素通りします。攻撃されても画面は普通に表示されるので、更新前後のスクリーンショットを比べても差分が出ません。壊れるのは認証の内側だけです。
そもそもこれは「更新で壊れる」問題ではなく、「古い版に脆弱性がある」問題です。検査が見るのは更新の安全性で、いま動いている版に既知の脆弱性があるかどうかは対象外です。効くのは検査ではなく、更新したあとの巡回でした。毎週見に行って、新しい版が出ていれば上げ直す。この形なら、3.16.4 に上がってしまっても翌週には 3.16.5 に移れます。
セキュリティ修正を当てる速さの話だと思っていたら、当てたあと追い続けられるかの話でした。CVSS 9.8 の脆弱性が、それを塞ぐための修正から生まれています。更新は、当てて完了ではなく、当ててからが本番です。
User Profile Builder を使っていて、まだ 3.16.5 より前なら、いま 3.16.6 に上げるのが早いです。
