# CVE-2025-14855: SureForms WordPress Plugin Stored XSS Proof of Concept - **Target:** WordPress Plugin "SureForms" - **Plugin Wordpress:** https://wordpress.org/plugins/sureforms/ - **Vulnerability Type:** Stored Cross-Site Scripting (XSS) - **CVE:** CVE-2025-14855 - **Refer:** https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/sureforms/sureforms-220-unauthenticated-stored-cross-site-scripting - **Authentication:** Unauthenticated (Guest/Public) - **Impact:** Remote Code Execution (RCE) via Admin Session Hijacking - **Discovered by:** https://nguyentiendung1006.wixsite.com/tiendung ## 1. Abstract A critical **Stored XSS** vulnerability exists in the SureForms plugin. The vulnerability stems from an insecure client-side implementation in `entries.js` where user input is programmatically **decoded** (reversing server-side sanitization) and then rendered using `dangerouslySetInnerHTML` without proper client-side sanitization. This allows unauthenticated attackers to inject malicious JavaScript payloads via standard form fields, bypassing WordPress's default `wp_kses` filters. ## 2. Version Identification To verify if a target site is running SureForms, inspect the translation file header which typically contains the version number. **Target URL:** `http://target-site.com/wp-content/plugins/sureforms/languages/sureforms.pot` **Verification Command:** ```bash curl -s "http://target-site.com/wp-content/plugins/sureforms/languages/sureforms.pot" | grep "Project-Id-Version" ``` ## 3. Reverse Engineering & Root Cause Analysis The vulnerability resides in the React-based admin interface responsible for viewing form entries (`entries.js`). ### 3.1. The "Auto-Decoder" Logic (The Bypass) In the minified `entries.js` file, there is a helper function (identified as `Xv` in the analyzed build) designed to handle HTML entities. **Code Logic (Reconstructed):** ```javascript // Function Xv: Pre-processing field values var Xv = function(input) { var value = input.value; // VULNERABILITY ROOT CAUSE: // If the string contains HTML entities (e.g., <), create a textarea, // inject the content, and extract the value. // This effectively DECODES HTML entities back to raw HTML tags. // Example: "<img ...>" becomes "" if (typeof value === "string" && value.match(/&[a-zA-Z0-9#]+;/)) { var textarea = document.createElement("textarea"); textarea.innerHTML = value; // Logic to revert sanitization if (textarea.value.includes("<") || textarea.value.includes(">")) { value = textarea.value; // Now 'value' contains RAW HTML } } return { ...input, value: value }; } ``` **Analysis:** This function defeats backend security. Even if WordPress correctly stores `