Hustle – Email Marketing, Lead Generation, Optins, Popups <= 7.8.10.2 - Missing Authorization to Unauthenticated Conversion Tracking Data Manipulation
Description
The Hustle – Email Marketing, Lead Generation, Optins, Popups plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the 'hustle_module_converted' AJAX action in all versions up to, and including, 7.8.10.2. This makes it possible for unauthenticated attackers to forge conversion tracking events for any Hustle module, including draft modules that are never displayed to users, thereby manipulating marketing analytics and conversion statistics.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=7.8.10.2What Changed in the Fix
Changes introduced in v7.8.11
Source Code
WordPress.org SVN# Research Plan: CVE-2026-2263 - Hustle Email Marketing Missing Authorization ## 1. Vulnerability Summary The **Hustle – Email Marketing, Lead Generation, Optins, Popups** plugin for WordPress is vulnerable to **Missing Authorization** in its conversion tracking logic. Specifically, the AJAX action…
Show full research plan
Research Plan: CVE-2026-2263 - Hustle Email Marketing Missing Authorization
1. Vulnerability Summary
The Hustle – Email Marketing, Lead Generation, Optins, Popups plugin for WordPress is vulnerable to Missing Authorization in its conversion tracking logic. Specifically, the AJAX action hustle_module_converted (handled via wp_ajax_nopriv_hustle_module_converted) lacks sufficient capability checks and validation. This allows unauthenticated attackers to programmatically submit conversion events for any module ID, including draft or private modules, leading to the manipulation of marketing analytics and conversion statistics.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
hustle_module_converted - Method: POST
- Authentication: None (Unauthenticated via
noprivregistration) - Parameters:
action:hustle_module_converted(Required)id: The integer ID of the Hustle module (e.g., popup or slide-in ID).module_id: Often used interchangeably withid.module_type: The type of module (e.g.,popup,slidein,embedded).nonce: A security nonce, typically localized on the frontend.
3. Code Flow (Inferred)
- Entry Point: A POST request is sent to
admin-ajax.phpwithaction=hustle_module_converted. - Hook Registration: The plugin registers
add_action( 'wp_ajax_nopriv_hustle_module_converted', ... )andadd_action( 'wp_ajax_hustle_module_converted', ... ), pointing to a handler (likely ininc/class-hustle-ajax.phporinc/hustle-functions.php). - Vulnerable Handler: The handler function retrieves the
module_idandmodule_typefrom the request. - Missing Authorization: The code fails to verify if the user has permissions to modify tracking data or, more importantly, fails to verify if the targeted
module_idis currently published and active. - Sink: The plugin calls a tracking method (e.g.,
Hustle_Tracking::save_tracking()) which executes a database query (usually on the{$wpdb->prefix}hustle_trackingtable) to increment the conversion count.
4. Nonce Acquisition Strategy
Hustle localizes tracking nonces for frontend use. To obtain a valid nonce unauthenticated:
- Identify/Create a Trigger: Navigate to any page where a Hustle module is active. If no module is active, we can create a simple published popup.
- Locate Nonce Variable: Hustle enqueues scripts that include a global variable containing the nonce.
- JS Object:
hustle_front_vars(inferred from standard Hustle frontend localization). - Key:
ajax_nonce.
- JS Object:
- Extraction Method:
- Navigate to the WordPress site.
- Use
browser_evalto extract the nonce:window.hustle_front_vars?.ajax_nonce.
5. Exploitation Strategy
Step 1: Discover Target Module ID
Identify a module ID to target. This can be an existing popup or a newly created draft.
- WP-CLI:
wp post list --post_type=hustle_popup --post_status=draft
Step 2: Obtain Frontend Nonce
Navigate to the homepage and extract the nonce.
- URL:
http://localhost:8080/ - JS:
window.hustle_front_vars.ajax_nonce
Step 3: Forge Conversion Request
Send a POST request to increment the conversion counter for the target ID.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Payload:
action=hustle_module_converted&id=[MODULE_ID]&module_id=[MODULE_ID]&module_type=popup&nonce=[NONCE] - Note: The
module_typemust match the actual type of the module (popup, slidein, etc.).
6. Test Data Setup
- Create a Draft Popup:
Note: Capture the ID from the output.wp post create --post_type=hustle_popup --post_title="Hidden Draft" --post_status=draft - Create a Public Popup (for Nonce):
wp post create --post_type=hustle_popup --post_title="Public Trigger" --post_status=publish - Verify Initial Stats:
Check the tracking table (if accessible) or use the plugin's internal methods via CLI to see conversion counts for the Draft ID.
7. Expected Results
- The AJAX request should return a successful response (likely
{"success":true}or a JSON object containing the new count). - The conversion statistics for the targeted module (including the draft) will increment in the database.
8. Verification Steps
- Database Inspection:
Query the tracking table directly to see if the count for the specificmodule_idincreased.wp db query "SELECT count FROM $(wp db prefix)hustle_tracking WHERE module_id=[ID] AND type='conversion'" - UI Verification:
If access to the admin dashboard is available, navigate to the Hustle "Popups" list and check the "Conversions" column for the Draft module.
9. Alternative Approaches
- Module Types: If
popupdoes not work, tryslidein,embedded, orsocial_sharing. - Bulk Manipulation: Attempt to send a loop of requests to significantly inflate the numbers (e.g., 100 conversions) to confirm the lack of rate limiting or authorization.
- Param Variation: If
idfails, ensuremodule_idis present, as some versions of the plugin transition between these parameter names.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.