TelSender <= 1.14.14 - Unauthenticated Stored Cross-Site Scripting via Telegram Chat Title
Description
The TelSender plugin for WordPress is vulnerable to DOM-Based Cross-Site Scripting in all versions up to, and including, 1.14.14. This is due to insufficient input sanitization when processing Telegram API responses containing attacker-controlled chat titles. This makes it possible for unauthenticated attackers to inject malicious scripts via Telegram chat titles that execute when an administrator opens the TelSender settings page and clicks the "Tested" button.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.14.14Source Code
WordPress.org SVNThis research plan focuses on the **TelSender** plugin vulnerability, where a Telegram chat title controlled by an unauthenticated user (on the Telegram side) can trigger Cross-Site Scripting (XSS) in the WordPress admin dashboard. ### 1. Vulnerability Summary The TelSender plugin (versions <= 1.14…
Show full research plan
This research plan focuses on the TelSender plugin vulnerability, where a Telegram chat title controlled by an unauthenticated user (on the Telegram side) can trigger Cross-Site Scripting (XSS) in the WordPress admin dashboard.
1. Vulnerability Summary
The TelSender plugin (versions <= 1.14.14) fails to sanitize Telegram API responses before rendering them in the administrative interface. Specifically, when an administrator uses the "Tested" (Connection Test) functionality, the plugin fetches data from the Telegram API (such as chat titles). An attacker can change a Telegram group/chat title to a malicious script. When the WordPress admin initiates the connection test, the plugin's JavaScript receives the malicious title and injects it into the DOM (typically using a method like .html()), leading to DOM-based XSS.
2. Attack Vector Analysis
- Endpoint: WordPress Admin Settings Page (typically
wp-admin/admin.php?page=telsender). - Vulnerable Action: Clicking the "Tested" / "Check Connection" button.
- Payload Delivery: Via the Telegram API. The attacker modifies a Telegram chat/group title that the bot is associated with.
- Authentication:
- Payload Injection: Unauthenticated (on the WordPress side; requires access to the Telegram chat).
- Payload Execution: Requires an Administrator to click the test button.
- Preconditions:
- The TelSender plugin must be configured with a valid (or dummy) Telegram Bot Token.
- The bot must be a member of a chat where the attacker can change the title.
3. Code Flow (Inferred)
- Admin UI: The administrator navigates to the TelSender settings and clicks a button (e.g.,
#telsender-test-btn). - AJAX Request: A JavaScript function (likely in
assets/js/admin.jsoradmin/js/telsender.js) sends an AJAX request toadmin-ajax.phpwith an action liketelsender_test_connection. - Server-Side Fetch: The PHP handler (likely in
admin/class-telsender-admin.php) useswp_remote_get()to call the Telegram API (https://api.telegram.org/bot<token>/getUpdatesorgetChat). - Data Return: The PHP handler receives the Telegram JSON response, extracts the
titlefield from thechatobject, and returns it to the JavaScript as part of a JSON response. - DOM Sink: The JavaScript success callback takes the returned title and updates a status message or log area:
The use of// Vulnerable Pattern success: function(response) { jQuery('#test-result-container').html("Connected to chat: " + response.chat_title); }.html()instead of.text()allows the payload inchat_titleto execute.
4. Nonce Acquisition Strategy
The "Tested" button is located within the Admin Settings page. To perform the AJAX request as an administrator:
- Identify Page: Use
wp_clito find the plugin's menu slug:wp eval "print_r( $GLOBALS['menu'] );"or check theadmin_menuhook in the source. - Navigate: Use
browser_navigateto reach the TelSender settings page. - Extract Nonce: Look for localized script data or hidden input fields.
- Common localization key:
telsender_paramsorts_ajax. - Command:
browser_eval("window.telsender_params?.nonce")orbrowser_eval("jQuery('#telsender_nonce').val()"). - Note: Since the exploit is triggered by a manual click in the browser, the nonce is handled automatically by the plugin's own scripts. The research goal is to ensure the payload is present when the button is clicked.
- Common localization key:
5. Exploitation Strategy
Since the test environment cannot connect to the real Telegram API, we will mock the Telegram API response using WordPress filters.
- Mock Telegram API: Create a small helper plugin or use
wp evalto hook intopre_http_request. This hook will intercept calls toapi.telegram.organd return a spoofed JSON object containing the XSS payload in the chat title. - Configure Plugin: Set a dummy Bot Token in TelSender settings.
- Trigger XSS:
- Navigate to the settings page as an Admin.
- Click the "Tested" button.
- Observe the execution of the payload (e.g.,
alert(document.domain)).
Payload:Chat <img src=x onerror="alert('XSS_SUCCESS_DOMAIN_'+document.domain)">
Mock Script (Conceptual):
add_filter('pre_http_request', function($pre, $args, $url) {
if (strpos($url, 'api.telegram.org') !== false) {
return [
'response' => ['code' => 200, 'message' => 'OK'],
'body' => json_encode([
'ok' => true,
'result' => [
[
'message' => [
'chat' => [
'id' => 123,
'title' => 'Test Group <img src=x onerror=alert(1)>'
]
]
]
]
])
];
}
return $pre;
}, 10, 3);
6. Test Data Setup
- Plugin Activation:
wp plugin activate telsender. - Settings Initialization:
wp option update telsender_settings '{"bot_token":"123456:ABC-DEF", "chat_id":"12345"}' --format=json - Mock Deployment: Deploy the
pre_http_requestfilter (via a drop-in orwp eval) to simulate the malicious Telegram response.
7. Expected Results
- The AJAX request to the connection test handler succeeds.
- The response contains the string:
Test Group <img src=x onerror=alert(1)>. - The browser's console or an alert box shows
1, confirming that the HTML was rendered directly into the DOM without escaping.
8. Verification Steps
- Observe DOM: Use
browser_evalto check if the malicious<img>tag exists in the result container.browser_eval("document.querySelector('#test-result-container img') !== null") - Check for Execution: Use a
console.logor a global variable in theonerrorpayload and check for its existence.
9. Alternative Approaches
- Stored XSS via Webhook: If the plugin supports webhooks, send a POST request directly to the webhook endpoint (usually unauthenticated) containing the malicious chat title. If the plugin stores this title in the database (e.g., in a "Recent Logs" option), the XSS will execute whenever the admin views the main plugin page, without needing to click "Tested".
- Search for Sink: Use
grep -r ".html(" .in the plugin'sassets/directory to find the exact line in JavaScript responsible for rendering the API response.
Summary
The TelSender plugin for WordPress is vulnerable to DOM-based Stored Cross-Site Scripting due to insufficient sanitization of Telegram chat titles retrieved via the Telegram API. An attacker can set a malicious script as a Telegram chat title, which is then executed in the administrator's browser when they perform a connection test in the plugin settings.
Vulnerable Code
// admin/class-telsender-admin.php (Inferred server-side handler) public function telsender_test_connection() { $token = get_option('telsender_bot_token'); $response = wp_remote_get("https://api.telegram.org/bot$token/getUpdates"); $body = json_decode(wp_remote_retrieve_body($response), true); // The chat title is taken directly from the API response without sanitization $chat_title = $body['result'][0]['message']['chat']['title']; wp_send_json_success(array('chat_title' => $chat_title)); } --- // assets/js/admin.js (Inferred client-side sink) $.ajax({ url: ajaxurl, type: 'POST', data: { action: 'telsender_test_connection', ... }, success: function(response) { if (response.success) { // Vulnerable sink using .html() instead of .text() $('#test-result-container').html("Connected to chat: " + response.data.chat_title); } } });
Security Fix
@@ -10,1 +10,1 @@ - $('#test-result-container').html("Connected to chat: " + response.data.chat_title); + $('#test-result-container').text("Connected to chat: " + response.data.chat_title); @@ -25,1 +25,1 @@ - wp_send_json_success(array('chat_title' => $chat_title)); + wp_send_json_success(array('chat_title' => sanitize_text_field($chat_title)));
Exploit Outline
1. Attacker gains access to a Telegram group or chat that the target WordPress site's bot is monitoring. 2. Attacker changes the Telegram chat title to a malicious XSS payload (e.g., `<img src=x onerror=alert(document.domain)>`). 3. Attacker waits for a site administrator to visit the TelSender settings page in the WordPress admin dashboard. 4. The administrator clicks the "Tested" or "Check Connection" button to verify the bot's functionality. 5. The plugin sends an AJAX request to the server, which fetches the malicious title from the Telegram API. 6. The server returns the payload to the administrator's browser, where the plugin's JavaScript renders it directly into the DOM using a vulnerable sink, executing the script.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.