YayMail <= 4.3.2 - Authenticated (Shop Manager+) Stored Cross-Site Scripting via Template Elements
Description
The YayMail – WooCommerce Email Customizer plugin for WordPress is vulnerable to Stored Cross-Site Scripting via settings in all versions up to, and including, 4.3.2 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with Shop Manager-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
<=4.3.2What Changed in the Fix
Changes introduced in v4.3.3
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-1943 (YayMail Stored XSS) ## 1. Vulnerability Summary The **YayMail – WooCommerce Email Customizer** plugin (versions <= 4.3.2) is vulnerable to **Authenticated Stored Cross-Site Scripting (XSS)**. The vulnerability exists because the plugin fails to sanitize …
Show full research plan
Exploitation Research Plan: CVE-2026-1943 (YayMail Stored XSS)
1. Vulnerability Summary
The YayMail – WooCommerce Email Customizer plugin (versions <= 4.3.2) is vulnerable to Authenticated Stored Cross-Site Scripting (XSS). The vulnerability exists because the plugin fails to sanitize and escape user-provided email template element settings before storing them in the database and subsequently rendering them in the admin dashboard.
While administrators typically have the unfiltered_html capability, Shop Managers and users in Multi-site environments do not. This plugin allows these lower-privileged users to inject malicious scripts into email templates, which will execute when an Administrator or any other user visits the YayMail editor or previews the affected template.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - AJAX Action:
yaymail_save_elements(inferred from plugin architecture for saving template data). - Vulnerable Parameter:
elements(a JSON-encoded string containing the structure and content of the email template). - Authentication: Required. Role must be Shop Manager or higher.
- Precondition: The site must be a Multi-site installation or have
DISALLOW_UNFILTERED_HTMLset totrue(standard for Shop Managers).
3. Code Flow
- Entry Point: The user interacts with the YayMail Editor UI (
wp-admin/admin.php?page=yaymail-settings). - Frontend Action: When the "Save" button is clicked, the React application bundled in
assets/dist/yaymail/yaymail-main.tsx-523766ce.jsgathers the state of all "elements" (text blocks, buttons, images). - Transmission: The application sends an AJAX POST request to
admin-ajax.phpwith the actionyaymail_save_elements. - Backend Processing:
- The server-side handler (typically in
YayMail\Controller\Customizer) receives theelementsparameter. - The handler fails to perform recursive sanitization on the JSON object's content fields (e.g., the
contentproperty of atextelement). - The raw HTML/Script payload is stored in the
wp_optionstable or a customyaymail_templatestable.
- The server-side handler (typically in
- Sink (Rendering): When a user (e.g., an Admin) loads the YayMail customizer, the plugin fetches the stored JSON. The React component
yaymail-customizer-element(referenced inyaymail-main-09390d33.css) renders the content, likely using an unsafe method likedangerouslySetInnerHTMLor failing to escape the data before it's injected into the DOM.
4. Nonce Acquisition Strategy
YayMail localizes its configuration and security nonces into a global JavaScript object.
- Identify the Page: The customizer is located at
wp-admin/admin.php?page=yaymail-settings. - Target Variable: Based on the plugin's structure, the localization object is
YayMailLocalization. - Execution Steps:
- Use
browser_navigateto go tohttp://localhost:8080/wp-admin/admin.php?page=yaymail-settings. - Use
browser_evalto extract the nonce:window.YayMailLocalization?.nonce
- Use
- Alternative: If
YayMailLocalizationis not found, checkYayMailSettings?.nonce.
5. Exploitation Strategy
The exploit involves sending a specially crafted JSON payload to the template saving endpoint.
Step 1: Authentication
Log in as a Shop Manager user.
Step 2: Extract Nonce and Template ID
Navigate to the YayMail settings page and extract the nonce and the current template ID (e.g., 7 for "New Order").
Step 3: Craft and Send Payload
Construct an AJAX POST request to save a malicious text element.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Content-Type:
application/x-www-form-urlencoded - Parameters:
action:yaymail_save_elements_wpnonce:[EXTRACTED_NONCE]template:[TEMPLATE_ID](e.g.,wc_email_new_order)elements:[{"id":"0.12345","type":"text","content":"<img src=x onerror=alert(document.domain)>","settings":{}}]
Step 4: Trigger Execution
Log in as an Administrator and navigate to wp-admin/admin.php?page=yaymail-settings. The alert should trigger when the customizer loads the "New Order" template.
6. Test Data Setup
- User Creation: Create a user with the
shop_managerrole. - Plugin Setup: Ensure WooCommerce is active (YayMail depends on it).
- Environment:
- Ensure
define( 'DISALLOW_UNFILTERED_HTML', true );is set inwp-config.phpto simulate a environment where even admins/shop managers are restricted (or simply use the Shop Manager account).
- Ensure
- Target Template: Identify a default template name, usually
wc_email_new_order.
7. Expected Results
- The
admin-ajax.phprequest should return a200 OKresponse, often with a JSON success body:{"success": true}. - Upon refreshing the editor page as an Admin, the HTML source of the preview pane or the editor element should contain the raw
<img src=x onerror=alert(document.domain)>string. - The browser will execute the
onerrorhandler, displaying an alert box.
8. Verification Steps
- Check Database: Use WP-CLI to inspect the saved template data:
Confirm that the output contains the unescaped script payload.wp option get yaymail_template_wc_email_new_order - Admin Login: Log in as
adminand navigate to the YayMail customizer. - DOM Inspection: Use
browser_evalto check if the payload exists in the DOM:document.body.innerHTML.includes('onerror=alert')
9. Alternative Approaches
- Payload Variance: If
imgtags are filtered, try<svg/onload=alert(1)>or<details/open/ontoggle=alert(1)>. - Attribute Injection: Instead of the
contentfield, try injecting into style or link attributes within the JSON:"settings":{"backgroundColor":"#ffffff\"><script>alert(1)</script>"} - Endpoint Discovery: If
yaymail_save_elementsis incorrect, search the JS bundle (yaymail-main.tsx-523766ce.js) for the stringaction:to find the correct AJAX action name. Look for patterns likeaction:"yaymail_...".
Summary
The YayMail plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) via email template elements due to a lack of sanitization when saving template data. This allows authenticated attackers with Shop Manager-level permissions or higher to inject arbitrary web scripts into templates, which will execute in the browser of any user (including administrators) who later accesses the YayMail customizer.
Vulnerable Code
// src/Models/TemplateModel.php:291 public static function update( $template_id, $data, $is_save_revision = false ) { if ( isset( $data['elements'] ) && is_array( $data['elements'] ) && isset( self::$meta_keys['elements'] ) ) { update_post_meta( $template_id, self::$meta_keys['elements'], $data['elements'] ); }
Security Fix
@@ -13,6 +13,7 @@ use YayMail\PostTypes\TemplatePostType; use YayMail\Shortcodes\ShortcodesExecutor; use YayMail\SupportedPlugins; +use YayMail\Utils\TemplateHelpers; /** * Template Model @@ -290,7 +291,8 @@ public static function update( $template_id, $data, $is_save_revision = false ) { if ( isset( $data['elements'] ) && is_array( $data['elements'] ) && isset( self::$meta_keys['elements'] ) ) { - update_post_meta( $template_id, self::$meta_keys['elements'], $data['elements'] ); + $elements_data = TemplateHelpers::sanitize_elements_recursive( $data['elements'] ); + update_post_meta( $template_id, self::$meta_keys['elements'], $elements_data ); } if ( ! empty( $data['background_color'] ) && isset( self::$meta_keys['background_color'] ) ) {
Exploit Outline
1. Authenticate as a user with Shop Manager permissions. 2. Access the YayMail settings page to retrieve the required security nonce (typically found in the `YayMailLocalization` global JavaScript object). 3. Identify the target template ID (e.g., `wc_email_new_order`). 4. Send a POST request to the `/wp-admin/admin-ajax.php` endpoint with the `action` set to `yaymail_save_elements`. 5. In the `elements` parameter, include a JSON-encoded payload representing a template element (such as a 'text' block) where the `content` property contains a malicious script (e.g., `<img src=x onerror=alert(document.domain)>`). 6. The payload will be stored in the post meta for that template without being sanitized. 7. The XSS triggers when an Administrator or another user opens the YayMail editor for that specific email template, as the stored HTML content is rendered into the customizer's DOM.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.