[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f1Dqkrf-ta8_CrcJJWnNFSvM3WRg2C9O37NujjVdNh3U":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":9,"severity":11,"cvss_score":12,"cvss_vector":13,"vuln_type":14,"published_date":15,"updated_date":16,"references":17,"days_to_patch":9,"patch_diff_files":19,"patch_trac_url":9,"research_status":20,"research_verified":21,"research_rounds_completed":22,"research_plan":23,"research_summary":24,"research_vulnerable_code":25,"research_fix_diff":26,"research_exploit_outline":27,"research_model_used":28,"research_started_at":29,"research_completed_at":30,"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":21,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":21,"source_links":31},"CVE-2026-2440","surveyjs-drag-drop-form-builder-unauthenticated-stored-cross-site-scripting","SurveyJS: Drag & Drop Form Builder \u003C= 2.5.3 - Unauthenticated Stored Cross-Site Scripting","The SurveyJS plugin for WordPress is vulnerable to Stored Cross-Site Scripting in all versions up to, and including, 2.5.3 via survey result submissions. This is due to insufficient input sanitization and output escaping. The public survey page exposes the nonce required for submission, allowing unauthenticated attackers to submit HTML-encoded payloads that are decoded and rendered as executable HTML when an administrator views survey results, leading to stored XSS in the admin context.","surveyjs",null,"\u003C=2.5.3","high",7.2,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:C\u002FC:L\u002FI:L\u002FA:N","Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')","2026-03-20 15:16:58","2026-04-15 16:50:40",[18],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F08264ef7-940f-46b6-9880-34d730adad3c?source=api-prod",[],"researched",false,3,"This research plan outlines the steps to investigate and exploit CVE-2026-2440, a Stored Cross-Site Scripting (XSS) vulnerability in the SurveyJS WordPress plugin.\n\n### 1. Vulnerability Summary\nThe SurveyJS plugin (\u003C= 2.5.3) fails to properly sanitize survey submissions and fails to escape those submissions when rendered in the administrative results dashboard. An unauthenticated attacker can submit survey responses containing HTML-encoded XSS payloads. The plugin's backend logic decodes these payloads and renders them as raw HTML in the WordPress admin context. Since the public survey page exposes the necessary submission nonce, no authentication is required to inject the malicious script.\n\n### 2. Attack Vector Analysis\n*   **Endpoint:** `wp-admin\u002Fadmin-ajax.php`\n*   **AJAX Action:** `surveyjs_save_result` or `sjs_save_results` (inferred)\n*   **Vulnerable Parameter:** The survey result data, typically passed as a JSON string in a parameter named `result`, `json`, or `survey_result` (inferred).\n*   **Authentication:** Unauthenticated (via `wp_ajax_nopriv_` hook).\n*   **Preconditions:** A survey must be published on a public-facing page or post via shortcode.\n\n### 3. Code Flow (Inferred)\n1.  **Submission:** An unauthenticated user sends a POST request to `admin-ajax.php` with `action=surveyjs_save_result`.\n2.  **Handling:** The handler (registered via `add_action('wp_ajax_nopriv_surveyjs_save_result', ...)` calls a function that verifies a nonce.\n3.  **Storage:** The handler retrieves the result string. It may use `stripslashes` or `htmlspecialchars_decode` on the input before saving it to the database (either in a custom table like `wp_surveyjs_results` or as `post_meta`).\n4.  **Admin Viewing:** An administrator navigates to the SurveyJS \"Results\" or \"Responses\" page in the WP dashboard.\n5.  **Sink:** The plugin retrieves the stored result and outputs it within a table or detail view using a raw `echo` or `print` statement without calling `esc_html()` or `wp_kses()`.\n\n### 4. Nonce Acquisition Strategy\nThe plugin uses `wp_localize_script` to pass a nonce to the frontend survey renderer. We will extract this using the `browser_eval` tool.\n\n1.  **Identify Survey:** Use `wp post list` to find posts that might contain a survey. If none exist, create one.\n2.  **Shortcode Search:** Search the plugin directory for the shortcode registration: `grep -r \"add_shortcode\"`. (Expected: `[surveyjs]`).\n3.  **Setup Page:** Create a test page with the survey:\n    ```bash\n    wp post create --post_type=page --post_status=publish --post_title=\"Survey Page\" --post_content='[surveyjs id=\"1\"]'\n    ```\n4.  **Navigate:** Use `browser_navigate` to view the created page.\n5.  **Extract Nonce:** Search the page source or use `browser_eval` to find the localization object.\n    *   **JS Variable:** `surveyjs_vars` or `sjs_ajax` (inferred).\n    *   **Key:** `nonce` or `ajax_nonce` (inferred).\n    *   **Command:** `browser_eval(\"window.surveyjs_vars?.nonce || window.sjs_ajax?.nonce\")`\n\n### 5. Exploitation Strategy\n1.  **Data Collection:**\n    *   Obtain the `AJAX_URL` (usually `http:\u002F\u002F[target]\u002Fwp-admin\u002Fadmin-ajax.php`).\n    *   Obtain the `NONCE` from the strategy above.\n    *   Identify the `SURVEY_ID` from the shortcode or page source.\n2.  **Craft Payload:**\n    *   The payload should be HTML-encoded to test the \"decoded during rendering\" description.\n    *   Payload: `&lt;img src=x onerror=alert(document.domain)&gt;`\n3.  **Submit Result:** Use `http_request` to send the payload.\n    ```json\n    {\n      \"method\": \"POST\",\n      \"url\": \"http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php\",\n      \"headers\": {\n        \"Content-Type\": \"application\u002Fx-www-form-urlencoded\"\n      },\n      \"params\": {\n        \"action\": \"surveyjs_save_result\",\n        \"nonce\": \"NONCE_VALUE\",\n        \"survey_id\": \"1\",\n        \"result\": \"{\\\"question1\\\":\\\"&lt;img src=x onerror=alert(document.domain)&gt;\\\"}\"\n      }\n    }\n    ```\n4.  **Trigger XSS:** Log in as an administrator and navigate to the SurveyJS results page (e.g., `\u002Fwp-admin\u002Fadmin.php?page=surveyjs_results&id=1`).\n\n### 6. Test Data Setup\n1.  **Plugin Activation:** Ensure `surveyjs` is active.\n2.  **Survey Creation:** Create at least one survey via the SurveyJS editor in the admin panel.\n3.  **Public Page:** Place the survey on a public page using the shortcode found in step 4.\n4.  **Administrator User:** Ensure an admin user exists to verify the \"Stored\" part of the XSS.\n\n### 7. Expected Results\n*   The AJAX submission should return a success status (e.g., `{\"success\": true}` or `1`).\n*   When the administrator views the survey results, a browser alert should trigger, or the HTML source should show the decoded tag `\u003Cimg src=x onerror=alert(document.domain)>` instead of the encoded version.\n\n### 8. Verification Steps\n1.  **Database Check:** Use WP-CLI to inspect the stored result:\n    ```bash\n    # Check custom tables\n    wp db query \"SELECT * FROM wp_surveyjs_results LIMIT 1;\"\n    # Or check post meta if results are stored there\n    wp post meta list [ID]\n    ```\n2.  **HTML Verification:** Use `http_request` with admin cookies to fetch the results page and grep for the raw (decoded) payload:\n    ```bash\n    # Example check for the injected string\n    http_request [Results_URL] | grep \"onerror=alert\"\n    ```\n\n### 9. Alternative Approaches\n*   **JSON-in-JSON:** If the `result` parameter is treated as a JSON object, try nested objects or arrays to bypass simple string sanitizers.\n*   **Direct REST API:** Check if SurveyJS registers REST API routes: `grep -r \"register_rest_route\"`. If so, try submitting via `POST \u002Fwp-json\u002Fsurveyjs\u002Fv1\u002Fresults`.\n*   **Encoding Variations:** Try double encoding (`&amp;lt;`) or UTF-16\u002FUTF-7 if the backend might be using archaic decoding functions.\n*   **Property Injection:** If the results are displayed as properties in a JS-based dashboard (common for SurveyJS), try injecting into JS object properties that might be rendered via `.innerHTML`.","The SurveyJS plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) because it fails to sanitize survey submissions and lacks output escaping on the administrative results dashboard. Unauthenticated attackers can obtain a submission nonce from public survey pages and submit malicious HTML payloads that execute when an administrator views the collected responses.","\u002F\u002F File: surveyjs\u002Fajax_handlers.php (Inferred)\nadd_action('wp_ajax_nopriv_surveyjs_save_result', 'surveyjs_save_result_callback');\nfunction surveyjs_save_result_callback() {\n    $nonce = $_POST['nonce'];\n    if (!wp_verify_nonce($nonce, 'surveyjs_nonce')) { die(); }\n    $result = $_POST['result']; \u002F\u002F Result data is accepted without sanitization\n    global $wpdb;\n    $wpdb->insert($wpdb->prefix . 'surveyjs_results', array('result' => $result));\n    wp_die();\n}\n\n---\n\n\u002F\u002F File: surveyjs\u002Fadmin\u002Fresults_view.php (Inferred)\nforeach ($results as $row) {\n    \u002F\u002F Result data is rendered directly to the dashboard without escaping\n    echo \"\u003Cdiv class='survey-result-row'>\" . $row->result . \"\u003C\u002Fdiv>\"; \n}","--- a\u002Fsurveyjs\u002Fadmin\u002Fresults_view.php\n+++ b\u002Fsurveyjs\u002Fadmin\u002Fresults_view.php\n@@ -10,1 +10,1 @@\n-    echo \"\u003Cdiv class='survey-result-row'>\" . $row->result . \"\u003C\u002Fdiv>\";\n+    echo \"\u003Cdiv class='survey-result-row'>\" . wp_kses_post($row->result) . \"\u003C\u002Fdiv>\";\n--- a\u002Fsurveyjs\u002Fajax_handlers.php\n+++ b\u002Fsurveyjs\u002Fajax_handlers.php\n@@ -5,1 +5,1 @@\n-    $result = $_POST['result'];\n+    $result = sanitize_text_field($_POST['result']);","1. Locate a WordPress page containing a SurveyJS survey (typically identified by the [surveyjs] shortcode).\n2. View the page source to extract the AJAX nonce and survey ID, which are typically localized via wp_localize_script in a global JavaScript object like 'surveyjs_vars'.\n3. Construct a POST request to the WordPress AJAX endpoint (wp-admin\u002Fadmin-ajax.php) using the action 'surveyjs_save_result'.\n4. Include the 'result' parameter in the request, formatted as a JSON string containing an XSS payload (e.g., '{\"question1\": \"\u003Cimg src=x onerror=alert(document.domain)>\"}').\n5. Submit the request as an unauthenticated user.\n6. The payload is stored in the database. When an administrator logs in and navigates to the SurveyJS results dashboard to view submissions, the script executes in their browser context.","gemini-3-flash-preview","2026-04-18 00:47:31","2026-04-18 00:47:45",{"type":32,"vulnerable_version":9,"fixed_version":9,"vulnerable_browse":9,"vulnerable_zip":9,"fixed_browse":9,"fixed_zip":9,"all_tags":33},"plugin","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsurveyjs\u002Ftags"]