CVE-2026-1943

YayMail <= 4.3.2 - Authenticated (Shop Manager+) Stored Cross-Site Scripting via Template Elements

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

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:N
Attack Vector
Network
Attack Complexity
High
Privileges Required
High
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=4.3.2
PublishedFebruary 17, 2026
Last updatedFebruary 18, 2026
Affected pluginyaymail

What Changed in the Fix

Changes introduced in v4.3.3

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# 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_HTML set to true (standard for Shop Managers).

3. Code Flow

  1. Entry Point: The user interacts with the YayMail Editor UI (wp-admin/admin.php?page=yaymail-settings).
  2. Frontend Action: When the "Save" button is clicked, the React application bundled in assets/dist/yaymail/yaymail-main.tsx-523766ce.js gathers the state of all "elements" (text blocks, buttons, images).
  3. Transmission: The application sends an AJAX POST request to admin-ajax.php with the action yaymail_save_elements.
  4. Backend Processing:
    • The server-side handler (typically in YayMail\Controller\Customizer) receives the elements parameter.
    • The handler fails to perform recursive sanitization on the JSON object's content fields (e.g., the content property of a text element).
    • The raw HTML/Script payload is stored in the wp_options table or a custom yaymail_templates table.
  5. 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 in yaymail-main-09390d33.css) renders the content, likely using an unsafe method like dangerouslySetInnerHTML or 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.

  1. Identify the Page: The customizer is located at wp-admin/admin.php?page=yaymail-settings.
  2. Target Variable: Based on the plugin's structure, the localization object is YayMailLocalization.
  3. Execution Steps:
    • Use browser_navigate to go to http://localhost:8080/wp-admin/admin.php?page=yaymail-settings.
    • Use browser_eval to extract the nonce:
      window.YayMailLocalization?.nonce
      
  4. Alternative: If YayMailLocalization is not found, check YayMailSettings?.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

  1. User Creation: Create a user with the shop_manager role.
  2. Plugin Setup: Ensure WooCommerce is active (YayMail depends on it).
  3. Environment:
    • Ensure define( 'DISALLOW_UNFILTERED_HTML', true ); is set in wp-config.php to simulate a environment where even admins/shop managers are restricted (or simply use the Shop Manager account).
  4. Target Template: Identify a default template name, usually wc_email_new_order.

7. Expected Results

  • The admin-ajax.php request should return a 200 OK response, 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 onerror handler, displaying an alert box.

8. Verification Steps

  1. Check Database: Use WP-CLI to inspect the saved template data:
    wp option get yaymail_template_wc_email_new_order
    
    Confirm that the output contains the unescaped script payload.
  2. Admin Login: Log in as admin and navigate to the YayMail customizer.
  3. DOM Inspection: Use browser_eval to check if the payload exists in the DOM:
    document.body.innerHTML.includes('onerror=alert')
    

9. Alternative Approaches

  • Payload Variance: If img tags are filtered, try <svg/onload=alert(1)> or <details/open/ontoggle=alert(1)>.
  • Attribute Injection: Instead of the content field, try injecting into style or link attributes within the JSON:
    "settings":{"backgroundColor":"#ffffff\"><script>alert(1)</script>"}
  • Endpoint Discovery: If yaymail_save_elements is incorrect, search the JS bundle (yaymail-main.tsx-523766ce.js) for the string action: to find the correct AJAX action name. Look for patterns like action:"yaymail_...".
Research Findings
Static analysis — not yet PoC-verified

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

--- /home/deploy/wp-safety.org/data/plugin-versions/yaymail/4.3.2/src/Models/TemplateModel.php	2025-12-17 13:01:26.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/yaymail/4.3.3/src/Models/TemplateModel.php	2026-02-12 15:49:00.000000000 +0000
@@ -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.