
Gravity Forms プラグイン(WordPress 用、バージョン 2.9.28 まででテスト済み)は、`gform_get_config` AJAX アクションの `form_ids` パラメータを介した、認証されていない反射型クロスサイトスクリプティング(XSS)に対して脆弱です。
gform_get_config の form_ids パラメータを介した未認証リフレクション型クロスサイトスクリプティング| フィールド | 値 |
|---|---|
| 影響を受けるソフトウェア | 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 ID | CVE-2026-4406 |
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
### 脆弱なアクション```
gform_get_config
args POSTパラメータは、form_ids配列を含むJSONオブジェクトを受け入れます。この配列内の値は、サニタイズなしでJSONレスポンス構造のオブジェクトキーとして使用されます:```json
{"form_ids":["ATTACKER_CONTROLLED_VALUE"]}
### レスポンス動作
サーバーは `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 -->
form_ids の値は整数として検証されておらず、サニタイズもフィルタリングもされていません。サーバーはHTMLタグやイベントハンドラを含む任意の文字列コンテンツを受け入れます。form_ids の値はHTMLエンティティエンコーディングなしでレスポンスボディに反映されます。<、>、"、' などの文字は変更されずにそのまま通過します。Content-Type: text/html; charset=UTF-8 で提供され、ブラウザにレスポンスボディをHTMLとして解析するよう指示します。反映された値内のHTMLタグは、ブラウザのHTMLパーサーによってインスタンス化されレンダリングされます。gform_get_config アクションで必要とされる config_nonce は、Gravity Formsフォームを読み込むすべてのページのJavaScript設定オブジェクト(gform_theme_config)に埋め込まれています。このnonceはすべてのページで同一であり、特定のユーザーセッションにバインドされていないため、認証されていないユーザーでも簡単に取得できます。この脆弱性は、連鎖して悪用可能な状態を生み出す複数の寄与する弱点の結果です。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
### 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
役割: 中核となる脆弱性 — XSS 状態の直接的な原因。
サーバーが form_ids の値を含む JSON レスポンスを構築する際、出力に HTML エンティティエンコーディングが適用されません。HTML で特別な意味を持つ文字(<、>、"、'、&)は、変更されずにそのままレスポンスボディに渡されます。PHP の htmlspecialchars()、esc_html()、JSON_HEX_TAG を指定した wp_json_encode()、または同等の出力エンコーディング関数は、form_ids の値がレスポンスに書き込まれる前に適用されていません。
証拠: リテラル文字列 <svg onload=alert(document.domain)> が、入力とバイト単位で完全に同一の形でレスポンスボディに出現します。<svg onload=alert(document.domain)> としては出現しません。
役割: コンテキストの昇格 — データの反映問題を実行可能なコードインジェクションへと変換します。
レスポンスボディには 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)
`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は以下のように確認された:
| ヘッダー | 値 | 悪用可能性への影響 |
|---|---|---|
X-Content-Type-Options | nosniff | 緩和効果なし — サーバーが明示的に text/html を宣言している |
X-Frame-Options | SAMEORIGIN | クロスオリジンからのiframeベースの悪用を防止するが、ポップアップ/リダイレクト経由の配信は依然として機能する |
Content-Security-Policy | frame-ancestors 'self'; | script-src ディレクティブなし — インラインスクリプトの実行は無制限 |
Referrer-Policy | strict-origin-when-cross-origin | 悪用可能性への影響なし |