CVE-2026-11592

Email Subscribers & Newsletters <= 5.9.27 - Missing Authorization to Authenticated (Contributor+) Settings Modification via ig_es_handle_request AJAX Action

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
5.9.28
Patched in
1d
Time to patch

Description

The Email Subscribers & Newsletters – Email Marketing, Post Notifications & Newsletter Plugin for WordPress plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 5.9.27. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for authenticated attackers, with contributor-level access and above, to overwrite plugin mail settings (from name and from email address), create audience lists, insert arbitrary contacts into those lists, create and overwrite newsletter broadcasts and post notifications, add workflows, and queue and dispatch mass email to arbitrary recipients.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=5.9.27
PublishedJuly 1, 2026
Last updatedJuly 2, 2026
Affected pluginemail-subscribers

What Changed in the Fix

Changes introduced in v5.9.28

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2026-11592 - Missing Authorization in Email Subscribers & Newsletters ## 1. Vulnerability Summary The **Email Subscribers & Newsletters** plugin (up to 5.9.27) contains a missing authorization vulnerability in its central AJAX dispatcher, `ig_es_handle_request`. While the actio…

Show full research plan

Research Plan: CVE-2026-11592 - Missing Authorization in Email Subscribers & Newsletters

1. Vulnerability Summary

The Email Subscribers & Newsletters plugin (up to 5.9.27) contains a missing authorization vulnerability in its central AJAX dispatcher, ig_es_handle_request. While the action is protected by a nonce, it fails to perform a capability check (e.g., current_user_can( 'manage_options' )). This allows any authenticated user with at least Contributor level access to invoke administrative controllers. These controllers can overwrite global plugin settings (like the "From" name and email), modify audience lists, create campaigns (newsletters), and trigger mass email dispatches.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: ig_es_handle_request
  • Vulnerable Hook: wp_ajax_ig_es_handle_request
  • Required Parameters:
    • action: ig_es_handle_request
    • security: A valid WordPress nonce for the action ig-es-admin-ajax-nonce.
    • ig_es_action: The internal route to the controller/method (e.g., settings/save_settings).
    • params: An array or JSON object containing the data for the specific action.
  • Authentication: Authenticated, Contributor role or higher.
  • Preconditions: The attacker must be logged in and obtain a nonce from the admin dashboard.

3. Code Flow

  1. Entry Point: The request hits admin-ajax.php with action=ig_es_handle_request.
  2. Dispatcher Registration: In lite/admin/class-email-subscribers-admin.php (or similar initialization files), the action wp_ajax_ig_es_handle_request is registered to a handler function (likely handle_request).
  3. Nonce Verification: The handler calls check_ajax_referer( 'ig-es-admin-ajax-nonce', 'security' ). This passes because the nonce is exposed to all users allowed in the admin area (including Contributors).
  4. Missing Check: The code proceeds to process ig_es_action and params without verifying if the user has manage_options or similar administrative capabilities.
  5. Routing: The dispatcher parses ig_es_action (e.g., settings/save_settings).
  6. Sink: It calls the relevant controller (e.g., ES_Settings_Controller::save_settings), which updates the WordPress options table or plugin database tables.

4. Nonce Acquisition Strategy

The nonce is localized for the admin environment. Even if a Contributor cannot access the "Settings" menu, the nonce is often enqueued on the general WordPress Dashboard or can be forced by visiting a plugin-specific URL.

  1. Login: Log in as a Contributor.
  2. Navigate: Go to /wp-admin/admin.php?page=es_campaigns. Even if WordPress shows an "Insufficient Permissions" error, the plugin's scripts are often enqueued because the page parameter matches the ES namespace.
  3. Extract: Use the browser context to read the ig_es_js_data object.
    • JS Variable: window.ig_es_js_data
    • Nonce Key: security
    • Command: browser_eval("window.ig_es_js_data?.security")

5. Exploitation Strategy

We will demonstrate the vulnerability by overwriting the plugin's "From Email" and "From Name" settings.

Step 1: Obtain Nonce

Navigate to the dashboard or an ES page and extract the nonce.

Step 2: Overwrite Settings

Send a POST request to admin-ajax.php.

  • URL: http://vulnerable-wp.local/wp-admin/admin-ajax.php
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded
  • Body:
    action=ig_es_handle_request&
    security=[EXTRACTED_NONCE]&
    ig_es_action=settings/save_settings&
    params[options][ig_es_from_name]=Pwned Name&
    params[options][ig_es_from_email]=attacker@evil.com
    

Step 3: Create a Malicious List (Alternative)

  • ig_es_action: lists/add_list
  • params[list][name]: Attacker List

6. Test Data Setup

  1. Target Version: Ensure Email Subscribers & Newsletters version is <= 5.9.27.
  2. User Creation:
    wp user create attacker attacker@example.com --role=contributor --user_pass=password
    
  3. Initialize Settings:
    wp option update ig_es_from_name "Original Admin"
    wp option update ig_es_from_email "admin@example.com"
    

7. Expected Results

  • The AJAX response should return a success status (likely {"success": true, "data": ...}).
  • The WordPress database will be updated with the attacker-controlled values.

8. Verification Steps

After performing the HTTP request, verify the state change using WP-CLI:

# Verify Name Overwrite
wp option get ig_es_from_name
# Expected: Pwned Name

# Verify Email Overwrite
wp option get ig_es_from_email
# Expected: attacker@evil.com

9. Alternative Approaches

If settings/save_settings is blocked or has additional checks, target the Campaigns or Contacts controllers:

  • Target: Add a new contact to the "Main" list (ID 1).

    • ig_es_action: contacts/save_contact
    • params[contact][email]: victim@target.com
    • params[contact][first_name]: Spammed
    • params[lists][]: 1
  • Target: Dispatch a test email.

    • ig_es_action: settings/send_test_email
    • params[test_email]: attacker@evil.com
Research Findings
Static analysis — not yet PoC-verified

Summary

The plugin's central AJAX dispatcher lacks a proper authorization check, allowing any authenticated user with at least Contributor-level permissions to execute administrative controllers. By utilizing a leaked nonce found in the WordPress admin dashboard, attackers can modify global plugin settings, manage subscriber lists, and dispatch mass email campaigns.

Vulnerable Code

// lite/admin/class-email-subscribers-admin.php line 429
			wp_localize_script( 'es-shadcn-dashboard', 'icegramExpressAdminData', array(
				'apiUrl' => admin_url( 'admin-ajax.php' ),
				'baseUrl' => ES_PLUGIN_URL . 'lite/admin/shadcn-frontend/dist/',
				'version' => $this->version,
				'isRtl' => is_rtl(),
				'security'    => wp_create_nonce( 'ig-es-admin-ajax-nonce' ),
				'plan' => ES()->get_plan(),
				'defaultRoute' => $default_route,
				'currentUser' => array(
					'displayName' => $current_user->display_name,
					'firstName' => $current_user->first_name,
					'lastName' => $current_user->last_name,
					'email' => $current_user->user_email,
				),

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/email-subscribers/5.9.27/email-subscribers.php /home/deploy/wp-safety.org/data/plugin-versions/email-subscribers/5.9.28/email-subscribers.php
--- /home/deploy/wp-safety.org/data/plugin-versions/email-subscribers/5.9.27/email-subscribers.php	2026-06-18 09:19:02.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/email-subscribers/5.9.28/email-subscribers.php	2026-06-24 11:08:14.000000000 +0000
@@ -3,7 +3,7 @@
  * Plugin Name: Icegram Express - Email Subscribers, Newsletters and Marketing Automation Plugin
  * Plugin URI: https://www.icegram.com/
  * Description: Add subscription forms on website, send HTML newsletters & automatically notify subscribers about new blog posts once it is published.
- * Version: 5.9.27
+ * Version: 5.9.28
  * Author: Icegram
  * Author URI: https://www.icegram.com/
  * Requires at least: 3.9
@@ -187,7 +187,7 @@
 /* ***************************** Initial Compatibility Work (End) ******************* */
 
 if ( ! defined( 'ES_PLUGIN_VERSION' ) ) {
-	define( 'ES_PLUGIN_VERSION', '5.9.27' );
+	define( 'ES_PLUGIN_VERSION', '5.9.28' );
 }
 
 // Plugin Folder Path.
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/email-subscribers/5.9.27/lite/admin/class-email-subscribers-admin.php /home/deploy/wp-safety.org/data/plugin-versions/email-subscribers/5.9.28/lite/admin/class-email-subscribers-admin.php
--- /home/deploy/wp-safety.org/data/plugin-versions/email-subscribers/5.9.27/lite/admin/class-email-subscribers-admin.php	2026-04-01 11:05:18.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/email-subscribers/5.9.28/lite/admin/class-email-subscribers-admin.php	2026-06-24 11:08:14.000000000 +0000
@@ -419,7 +419,20 @@
 					}
 				}
 			}
+
+			$unsubscribe_feedbacks = array();
+			if ( class_exists( 'IG_ES_Unsubscribe_Feedback' ) ) {
+				$unsubscribe_feedback_instance = new IG_ES_Unsubscribe_Feedback();
+				$unsubscribe_feedbacks = $unsubscribe_feedback_instance->get_default_unsubscribe_feedbacks();
+			}
+
 			
+			$unsubscribe_feedbacks = array();
+			if ( class_exists( 'IG_ES_Unsubscribe_Feedback' ) ) {
+				$unsubscribe_feedback_instance = new IG_ES_Unsubscribe_Feedback();
+				$unsubscribe_feedbacks = $unsubscribe_feedback_instance->get_default_unsubscribe_feedbacks();
+			}
+
 			wp_localize_script( 'es-shadcn-dashboard', 'icegramExpressAdminData', array(
 				'apiUrl' => admin_url( 'admin-ajax.php' ),
 				'baseUrl' => ES_PLUGIN_URL . 'lite/admin/shadcn-frontend/dist/',
@@ -429,6 +442,14 @@
 				'security'    => wp_create_nonce( 'ig-es-admin-ajax-nonce' ),
 				'plan' => ES()->get_plan(),
 				'defaultRoute' => $default_route,
+				'campaignStatus' => array(
+					'DRAFT' => IG_ES_CAMPAIGN_STATUS_IN_ACTIVE,
+					'ACTIVE' => IG_ES_CAMPAIGN_STATUS_ACTIVE,
+					'SCHEDULED' => IG_ES_CAMPAIGN_STATUS_SCHEDULED,
+					'QUEUED' => IG_ES_CAMPAIGN_STATUS_QUEUED,
+					'PAUSED' => IG_ES_CAMPAIGN_STATUS_PAUSED,
+					'FINISHED' => IG_ES_CAMPAIGN_STATUS_FINISHED,
+				),
 				'currentUser' => array(
 					'displayName' => $current_user->display_name,
 					'firstName' => $current_user->first_name,
@@ -450,6 +471,7 @@
 					'ig_es_track_utm' => get_option( 'ig_es_track_utm', 'no' ),
 				),
 				'pricingBanner' => Email_Subscribers_Pricing::get_pricing_banner_config(),
+				'unsubscribeFeedbacks' => $unsubscribe_feedbacks,
 			) );
 			wp_register_style( 'es-shadcn-dashboard', plugin_dir_url( __FILE__ ) . 'shadcn-frontend/dist/index.css', array(), $this->version );
 			wp_enqueue_script( 'es-shadcn-dashboard' );

Exploit Outline

To exploit this vulnerability, an attacker first authenticates with Contributor-level access and retrieves the `ig-es-admin-ajax-nonce` from the `icegramExpressAdminData` object localized in the admin area's JavaScript. The attacker then sends a POST request to `/wp-admin/admin-ajax.php` with the `action` parameter set to `ig_es_handle_request`. By setting the `ig_es_action` parameter to a sensitive internal route like `settings/save_settings` or `campaigns/save_campaign` and providing a valid nonce, the attacker can bypass capability checks to overwrite plugin settings (e.g., changing the 'From' email address), manipulate audience lists, or trigger email dispatches.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.