Smartsupp – live chat, AI shopping assistant and chatbots <= 3.9.1 - Authenticated (Subscriber+) Stored Cross-Site Scripting
Description
The Smartsupp – live chat, AI shopping assistant and chatbots plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'code' parameter in all versions up to, and including, 3.9.1 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with Subscriber-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=3.9.1Source Code
WordPress.org SVNThis research plan focuses on exploiting a Stored Cross-Site Scripting (XSS) vulnerability in the **Smartsupp – live chat, AI shopping assistant and chatbots** plugin (CVE-2025-12448). Since source files were not provided, this plan is based on the vulnerability description and common patterns found…
Show full research plan
This research plan focuses on exploiting a Stored Cross-Site Scripting (XSS) vulnerability in the Smartsupp – live chat, AI shopping assistant and chatbots plugin (CVE-2025-12448). Since source files were not provided, this plan is based on the vulnerability description and common patterns found in live-chat plugins.
1. Vulnerability Summary
The Smartsupp plugin fails to adequately sanitize and escape the code parameter when saving its settings. This parameter is intended to hold the Smartsupp chat integration script. Because the plugin allows users with Subscriber-level permissions (or higher) to update this value, and subsequently renders it unescaped on both the frontend and the admin dashboard, an attacker can inject arbitrary JavaScript.
2. Attack Vector Analysis
- Vulnerable Endpoint:
admin-ajax.phporwp-admin/options.php. - Vulnerable Parameter:
code(or potentiallysmartsupp_code/chat_code- inferred). - Authentication: Authenticated (Subscriber+).
- Preconditions: The plugin must be active. The attacker needs valid Subscriber credentials.
- Sink: The injected code is likely stored in the
wp_optionstable and rendered in the<head>or<footer>of all public-facing pages and/or the plugin's admin settings page.
3. Code Flow (Inferred)
- Entry Point: An AJAX action (e.g.,
wp_ajax_smartsupp_save_settings) or a settings save hook (e.g.,admin_init) is registered. - Lack of Authorization: The handler fails to check
current_user_can('manage_options'), instead only checking foris_user_logged_in()or a lower capability likeread. - Insecure Storage: The handler receives the
codeparameter and callsupdate_option('smartsupp_chat_code', $_POST['code'])without usingsanitize_text_fieldorwp_kses. - Insecure Output: A frontend hook (e.g.,
wp_headorwp_footer) callsget_option('smartsupp_chat_code')andechoes it directly withoutesc_js()oresc_html().
4. Nonce Acquisition Strategy
To update settings, the plugin likely requires a WordPress nonce localized into the admin dashboard or the settings page.
- Identify Script Enqueue: The plugin likely enqueues its settings scripts on its own menu page.
- Create Setup: The agent will log in as a Subscriber and navigate to the Smartsupp settings page (usually
/wp-admin/admin.php?page=smartsupp-settings). - Extraction:
- The agent will use
browser_evalto look for localized data. - Inferred Variable Name:
window.smartsuppDataorwindow.smartsupp_settings. - Action:
browser_eval("window.smartsuppData?.nonce")orbrowser_eval("document.querySelector('#_wpnonce')?.value").
- The agent will use
- Bypass Check: If no nonce check exists in the AJAX handler (a common oversight), the agent will attempt the request without it first.
5. Exploitation Strategy
The exploit will attempt to overwrite the chat integration code with a malicious script.
- Step 1: Authenticate as a Subscriber.
- Step 2: Locate the AJAX action. (The agent will grep the plugin directory for
wp_ajax_to find the exact action string). - Step 3: Prepare the payload:
</script><script>alert(document.domain);// - Step 4: Send the HTTP POST request via
http_request:- URL:
https://target.example.com/wp-admin/admin-ajax.php - Content-Type:
application/x-www-form-urlencoded - Body:
(Note: The exact action name and nonce key will be refined after the agent greps the source code.)action=smartsupp_save_settings&code=</script><script>alert(document.domain);//&_wpnonce=[EXTRACTED_NONCE]
- URL:
6. Test Data Setup
- Plugin Installation: Install and activate
smartsupp-live-chatversion 3.9.1. - User Creation: Create a user with the
subscriberrole.wp user create attacker attacker@example.com --role=subscriber --user_pass=password123
- Public Page: Ensure at least one public post exists to verify frontend rendering.
wp post create --post_type=post --post_status=publish --post_title="Vulnerable Page"
7. Expected Results
- Response: The AJAX handler should return a
200 OKor a JSON success message (e.g.,{"success":true}). - Storage: The
smartsupp_chat_code(or similar) option in the database will contain the raw<script>tag. - Execution: When any user (including the Admin) visits the homepage, a JavaScript alert box will appear.
8. Verification Steps
- Database Check: Use WP-CLI to verify the option is stored unsanitized:
wp option get smartsupp_chat_code(or the actual option name found during research).
- Frontend Check: Use
http_requestto fetch the homepage and verify the payload exists in the HTML:http_request("GET", "https://target.example.com/")- Confirm the presence of
alert(document.domain).
9. Alternative Approaches
- Settings API: If the plugin uses the standard WordPress Settings API (
options.php), the Subscriber might be able to POST directly towp-admin/options.phpif the option group was registered with__return_truefor the capability check or no capability check at all. - REST API: Check for any registered REST routes using
register_rest_routethat might allow updating settings without properpermission_callbackchecks. - Blind Payload: If the XSS does not fire on the frontend, check the Admin dashboard (specifically the Smartsupp settings page) to see if the payload executes there (Admin-only XSS).
Summary
The Smartsupp plugin for WordPress is vulnerable to Stored Cross-Site Scripting due to a lack of authorization checks and input sanitization in its settings update functionality. This allows authenticated attackers with Subscriber-level permissions to save malicious JavaScript in the 'code' parameter, which is then rendered unescaped on site pages.
Vulnerable Code
// File: smartsupp-live-chat/src/Smartsupp/Admin.php (inferred logic) // The plugin registers an AJAX action to save settings without performing capability checks. add_action('wp_ajax_smartsupp_save_settings', 'smartsupp_save_settings_handler'); function smartsupp_save_settings_handler() { // Vulnerability: No check for current_user_can('manage_options') // Vulnerability: No nonce verification if (isset($_POST['code'])) { // Vulnerability: Direct storage of unsanitized input update_option('smartsupp_chat_code', $_POST['code']); } wp_send_json_success(); } --- // File: smartsupp-live-chat/src/Smartsupp/Frontend.php (inferred logic) // The stored code is echoed directly onto the page. add_action('wp_head', 'smartsupp_render_chat_code'); function smartsupp_render_chat_code() { $code = get_option('smartsupp_chat_code'); if ($code) { echo $code; // Vulnerability: Unescaped output } }
Security Fix
@@ -10,6 +10,14 @@ function smartsupp_save_settings_handler() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 ); + return; + } + + check_ajax_referer( 'smartsupp_save_settings', 'nonce' ); + if ( isset( $_POST['code'] ) ) { - update_option( 'smartsupp_chat_code', $_POST['code'] ); + update_option( 'smartsupp_chat_code', wp_kses_post( $_POST['code'] ) ); } wp_send_json_success(); }
Exploit Outline
1. Authenticate to the WordPress site as a user with Subscriber-level privileges. 2. Identify the AJAX action used by the plugin to save settings (e.g., 'smartsupp_save_settings'). 3. Locate or extract a valid AJAX nonce if required (though the vulnerability description suggests an authorization bypass, meaning a nonce might be absent or not checked for Subscribers). 4. Send a POST request to /wp-admin/admin-ajax.php with the 'action' parameter set to the plugin's save handler and the 'code' parameter containing a malicious script payload (e.g., "</script><script>alert(document.domain)</script>"). 5. The plugin saves the payload into the site's options table without sanitization. 6. Visit any page on the site where the Smartsupp chat widget is rendered. The malicious script will execute in the context of the user's browser session.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.