CVE-2026-23807

WP Telegram Widget and Join Link <= 2.2.13 - Reflected Cross-Site Scripting

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

Description

The WP Telegram Widget and Join Link plugin for WordPress is vulnerable to Reflected Cross-Site Scripting in versions up to, and including, 2.2.13 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.2.13
PublishedMarch 23, 2026
Last updatedMarch 26, 2026
Affected pluginwptelegram-widget

What Changed in the Fix

Changes introduced in v2.2.14

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

input type="hidden" name="' . $name . '" value="' . $value . '" />'; ``` If `Shared::$use_ugly_urls` is true, this is a *very* direct sink for `$username` (passed as `$value`). * `Shared::$use_ugly_urls` is a class property. Let's see if it's set anywhere. In `includes…

Show full research plan

input type="hidden" name="' . $name . '" value="' . $value . '" />';
```
If Shared::$use_ugly_urls is true, this is a very direct sink for $username (passed as $value).

*   `Shared::$use_ugly_urls` is a class property. Let's see if it's set anywhere.
    In `includes/Main.php` (not provided), it likely checks `get_option('permalink_structure')`.
    If permalinks are default ("Plain"), `use_ugly_urls` is true.

*   To be safe, I will provide a payload that covers both cases:
    1.  Reflection in `action="..."`
    2.  Reflection in `value="..."`

*   Payload: `WPTelegram" onfocus="alert(1)" autofocus="true` (to trigger on the hidden input or form).
*   Or simpler: `WPTelegram"><script>alert(1)</script>` to break out of the tag entirely.

*   The `username` parameter.
*   The endpoint is `/?wptelegram=widget&module=widget&action=view&username=...` (inferred from `get_injected_form_fields` keys).
*   Wait, the `get_injected_form_fields` says:
    ```php
    'core'     => 'wptelegram',
    'module'   => 'widget',
Research Findings
Static analysis — not yet PoC-verified

Summary

The WP Telegram Widget and Join Link plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via the `username` parameter in versions up to and including 2.2.13. This occurs because the parameter is reflected into hidden form fields and used in unescaped regular expressions, allowing unauthenticated attackers to execute arbitrary JavaScript in the context of a user's browser.

Vulnerable Code

// shared/embed/AjaxWidget.php:140
$pattern = '/(?<=href="\/s\/' . $username . '\?[^" ]*?(?:before|after)=\d+[^" ]*?(?=")/i';

---

// shared/embed/AjaxWidget.php:201
foreach ( $fields as $name => $value ) {

    $html .= '<input type="hidden" name="' . $name . '" value="' . $value . '" />';
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/wptelegram-widget/2.2.13/shared/embed/AjaxWidget.php /home/deploy/wp-safety.org/data/plugin-versions/wptelegram-widget/2.2.14/shared/embed/AjaxWidget.php
--- /home/deploy/wp-safety.org/data/plugin-versions/wptelegram-widget/2.2.13/shared/embed/AjaxWidget.php	2024-01-26 15:04:50.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wptelegram-widget/2.2.14/shared/embed/AjaxWidget.php	2026-01-15 09:39:58.000000000 +0000
@@ -37,7 +37,7 @@
 
 			$url = sanitize_text_field( wp_unslash( $_GET['url'] ) );
 
-			if ( ! preg_match( '/\Ahttps:\/\/t\.me\/s\/' . $username . '.*/i', $url ) ) {
+			if ( ! preg_match( '/\Ahttps:\/\/t\.me\/s\/' . preg_quote( $username, '/' ) . '.*/i', $url ) ) {
 				exit;
 			}
 
@@ -140,7 +140,7 @@
 	 */
 	public static function replace_tg_links( $content, $username ) {
 
-		$pattern = '/(?<=href=")\/s\/' . $username . '\?[^" ]*?(?:before|after)=\d+[^" ]*?(?=")/i';
+		$pattern = '/(?<=href=")\/s\/' . preg_quote( $username, '/' ) . '\?[^" ]*?(?:before|after)=\d+[^" ]*?(?=")/i';
 
 		// Replace the ajax links.
 		$content = preg_replace_callback(
@@ -170,7 +170,7 @@
 		$content = preg_replace_callback(
 			$pattern,
 			function ( $matches ) use ( $username ) {
-				return str_replace( $matches[1], "https://t.me/{$username}", $matches[0] );
+				return str_replace( $matches[1], 'https://t.me/' . esc_attr( $username ), $matches[0] );
 			},
 			$content
 		);
@@ -201,7 +201,7 @@
 
 			foreach ( $fields as $name => $value ) {
 
-				$html .= '<input type="hidden" name="' . $name . '" value="' . $value . '" />';
+				$html .= '<input type="hidden" name="' . esc_attr( $name ) . '" value="' . esc_attr( $value ) . '" />';
 			}
 		}

Exploit Outline

To exploit this vulnerability, an attacker identifies the AJAX widget endpoint, typically accessed via the query parameters `/?wptelegram=widget&module=widget&action=view`. The attacker then crafts a malicious link targeting the `username` parameter. If the site is configured with 'Plain' permalinks (which enables the `use_ugly_urls` flag), the plugin reflects the `username` directly into the `value` attribute of a hidden `<input>` field without escaping. A payload like `WPTelegram"><script>alert(document.domain)</script>` will break out of the HTML attribute and execute the script when the victim clicks the link.

Check if your site is affected.

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