YayMail <= 4.3.2 - Missing Authorization to Authenticated (Shop Manager+) Arbitrary Options Update via 'yaymail_import_state' AJAX Action
Description
The YayMail – WooCommerce Email Customizer plugin for WordPress is vulnerable to unauthorized modification of data that can lead to privilege escalation due to a missing capability check on the `yaymail_import_state` AJAX action in all versions up to, and including, 4.3.2. This makes it possible for authenticated attackers, with Shop Manager-level access and above, to update arbitrary options on the WordPress site. This can be leveraged to update the default role for registration to administrator and enable user registration for attackers to gain administrative user access to a vulnerable site.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:HTechnical Details
What Changed in the Fix
Changes introduced in v4.3.3
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-1937 ## 1. Vulnerability Summary The **YayMail – WooCommerce Email Customizer** plugin (versions <= 4.3.2) contains a missing authorization vulnerability in its AJAX handler for the `yaymail_import_state` action. While the action is intended for importing emai…
Show full research plan
Exploitation Research Plan: CVE-2026-1937
1. Vulnerability Summary
The YayMail – WooCommerce Email Customizer plugin (versions <= 4.3.2) contains a missing authorization vulnerability in its AJAX handler for the yaymail_import_state action. While the action is intended for importing email template states, the implementation fails to verify if the requesting user has the manage_options capability. Instead, it only requires a valid nonce and the permissions usually associated with a Shop Manager. This allows an authenticated user with Shop Manager privileges to update arbitrary WordPress options, leading to full site takeover (Privilege Escalation).
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Method:
POST - Action:
yaymail_import_state - Vulnerable Parameter: Likely a
stateoroptionsparameter (inferred from the action name) that maps keys toupdate_option(). - Required Capability: Authenticated user with Shop Manager role (or any role that can access the YayMail admin interface).
- Preconditions:
- Plugin YayMail <= 4.3.2 installed and active.
- WooCommerce installed (to have the Shop Manager role).
- An account with the
shop_managerrole.
3. Code Flow (Inferred)
- Entry Point:
admin-ajax.phpreceives a request withaction=yaymail_import_state. - Hook Registration: The plugin likely registers the action in a class constructor or
inithook:add_action('wp_ajax_yaymail_import_state', [$this, 'import_state_callback']); - Handler Logic: The callback function (likely in an
includes/orclasses/PHP file not provided in the source snippet) performs acheck_ajax_referer('yaymail_nonce', 'nonce')(or similar). - Authorization Failure: The code fails to call
current_user_can('manage_options'). - Sink: The code iterates through the user-provided data and calls
update_option($key, $value)for each key-value pair in the payload.
4. Nonce Acquisition Strategy
Since this is an authenticated AJAX vulnerability, the nonce is required. The nonce is likely localized for the YayMail admin interface.
- Identify the Admin Page: The YayMail interface is usually at
wp-admin/admin.php?page=yaymail-settings. - Navigate and Inspect:
- Log in as a Shop Manager.
- Navigate to the YayMail settings page.
- Extract Nonce via Browser Eval:
The plugin useswp_localize_scriptto pass data to its React-based frontend (yaymail-main.tsx). Based on standard YayMail patterns, the global object is likelyyaymail_localizeorYayMailData.- Action to try:
browser_eval("window.yaymail_localize?.nonce")orbrowser_eval("window.YayMailData?.nonce"). - Verification: Search the page source for "nonce" to find the exact object name if the above fails.
- Action to try:
5. Exploitation Strategy
The goal is to enable user registration and set the default role to administrator.
Step-by-Step Plan:
Setup: Create a Shop Manager user and log in.
Nonce Extraction:
- Navigate to
wp-admin/admin.php?page=yaymail-settings. - Run
browser_evalto extract the nonce.
- Navigate to
Payload Construction:
The "import state" functionality likely expects a key representing the option or a specific array structure. Based on "Arbitrary Options Update," we will attempt to pass the options directly.- Target Options:
users_can_register:1default_role:administrator
- Target Options:
Execute Request:
Send the POST request toadmin-ajax.php.HTTP Request (Targeted):
POST /wp-admin/admin-ajax.php HTTP/1.1 Content-Type: application/x-www-form-urlencoded action=yaymail_import_state&nonce=[EXTRACTED_NONCE]&state[users_can_register]=1&state[default_role]=administratorNote: If
stateis not the correct parameter name, trydata,options, or a raw JSON body if the plugin usesphp://input.
6. Test Data Setup
- Plugin: Install YayMail version 4.3.2.
- WooCommerce: Ensure WooCommerce is active.
- Attacker User:
wp user create attacker attacker@example.com --role=shop_manager --user_pass=password - Baseline Check:
wp option get users_can_register(Expected: 0)wp option get default_role(Expected: subscriber)
7. Expected Results
- The AJAX request should return a
200 OKor a JSON success message (e.g.,{"success": true}). - The WordPress options
users_can_registeranddefault_rolewill be updated in the database.
8. Verification Steps
After the HTTP request, verify the state change using WP-CLI:
- Check if registration is enabled:
wp option get users_can_register(Success:1) - Check the default role:
wp option get default_role(Success:administrator) - (Optional) Verify an unauthenticated user can now register as an admin:
curl -X POST http://localhost:8080/wp-login.php?action=register -d "user_login=eviladmin&user_email=evil@example.com"
9. Alternative Approaches
If the state[option_name]=value format fails:
- JSON Payload: Some modern WordPress plugins use JSON for state imports.
- Try:
Content-Type: application/jsonwith body{"action": "yaymail_import_state", "nonce": "...", "state": {"users_can_register": "1", "default_role": "administrator"}}.
- Try:
- Option Nesting: The plugin might expect the options inside a specific key used by YayMail settings (e.g.,
state[yaymail_settings][users_can_register]). - Parameter Guessing: If
stateis incorrect, check the JS source (yaymail-main.tsx-523766ce.js) for the stringyaymail_import_stateto see how the frontend assembles the request. (The provided JS is minified, so look for theactionstring and adjacent property names).
Summary
The YayMail plugin for WordPress (versions <= 4.3.2) is vulnerable to unauthorized modification of data due to a missing authorization check and lack of option key filtering in the 'yaymail_import_state' AJAX action. This allows authenticated attackers, such as Shop Managers, to update arbitrary WordPress options, enabling them to change the default registration role to administrator and take full control of the site.
Vulnerable Code
// src/Models/MigrationModel.php // Line 141 in 4.3.2 // Restore backed-up options foreach ( $backup['options'] as $option ) { update_option( $option->option_name, maybe_unserialize( $option->option_value ) ); } --- // src/License/RestAPI.php // Line 140 in 4.3.2 public function permission_callback() { return true; }
Security Fix
@@ -140,6 +140,6 @@ } public function permission_callback() { - return true; + return current_user_can( 'manage_options' ); } } @@ -141,7 +141,10 @@ // Restore backed-up options foreach ( $backup['options'] as $option ) { - update_option( $option->option_name, maybe_unserialize( $option->option_value ) ); + // Only restore options that belong to YayMail (same pattern as export) + if ( strpos( $option->option_name, 'yaymail' ) !== false ) { + update_option( $option->option_name, maybe_unserialize( $option->option_value ) ); + } } // Remove the succeeded migration log from db
Exploit Outline
The exploit requires an authenticated session with Shop Manager or higher privileges. 1. Log in to the target WordPress site as a Shop Manager. 2. Navigate to the YayMail settings page and extract the security nonce from the global JavaScript object (e.g., `yaymail_localize.nonce`). 3. Send a POST request to `/wp-admin/admin-ajax.php` with the action `yaymail_import_state`. 4. Include a payload representing an imported state containing target options. To achieve privilege escalation, set the option `users_can_register` to `1` and `default_role` to `administrator`. 5. Because the plugin lacks a `manage_options` capability check on this action and fails to validate that the provided option names belong to the plugin, it calls `update_option()` on the attacker-controlled keys. 6. Once the options are updated, navigate to the public registration page and create a new account, which will be granted administrative privileges.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.