WP-Optimize <= 4.5.0 - Missing Authorization to Authenticated (Subscriber+) Plugin Settings Update and Image Manipulation
Description
The WP-Optimize plugin for WordPress is vulnerable to unauthorized access of functionality due to missing capability checks in the `receive_heartbeat()` function in `includes/class-wp-optimize-heartbeat.php` in all versions up to, and including, 4.5.0. This is due to the Heartbeat handler directly invoking `Updraft_Smush_Manager_Commands` methods without verifying user capabilities, nonce tokens, or the allowed commands whitelist that the normal AJAX handler (`updraft_smush_ajax`) enforces. This makes it possible for authenticated attackers, with Subscriber-level access and above, to invoke admin-only Smush operations including reading log files (`get_smush_logs`), deleting all backup images (`clean_all_backup_images`), triggering bulk image processing (`process_bulk_smush`), and modifying Smush options (`update_smush_options`).
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:LTechnical Details
What Changed in the Fix
Changes introduced in v4.5.1
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-2712 ## 1. Vulnerability Summary The **WP-Optimize** plugin (up to version 4.5.0) contains an **Incorrect Authorization** vulnerability in its Heartbeat API integration. Specifically, the `receive_heartbeat()` function in `includes/class-wp-optimize-heartbeat.…
Show full research plan
Exploitation Research Plan: CVE-2026-2712
1. Vulnerability Summary
The WP-Optimize plugin (up to version 4.5.0) contains an Incorrect Authorization vulnerability in its Heartbeat API integration. Specifically, the receive_heartbeat() function in includes/class-wp-optimize-heartbeat.php fails to perform capability checks (current_user_can) or verify security nonces before executing commands intended for administrators.
The Heartbeat handler acts as a proxy, directly invoking methods in the Updraft_Smush_Manager_Commands class. While the standard AJAX handler (updraft_smush_ajax) properly restricts access, this Heartbeat-based entry point is accessible to any authenticated user, including those with Subscriber-level permissions. This allows an attacker to manipulate image optimization settings, delete backup images, and view logs.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
heartbeat - Method:
POST - Authentication: Required (Subscriber+)
- Vulnerable Hook:
heartbeat_received(Filter) - Vulnerable File:
includes/class-wp-optimize-heartbeat.php - Vulnerable Function:
receive_heartbeat() - Impact: Unauthorized modification of plugin settings (
update_smush_options), deletion of data (clean_all_backup_images), and information disclosure (get_smush_logs).
3. Code Flow
- Entry Point: A user logged into WordPress (even as a Subscriber) triggers a Heartbeat request. This is a standard POST request to
admin-ajax.phpwithaction=heartbeat. - Hook Execution: WordPress triggers the
heartbeat_receivedfilter. - Vulnerable Handler:
WP_Optimize_Heartbeat::receive_heartbeat($response, $data)is invoked. - Logic Path:
- The function checks if
$data['wp-optimize']is present. - It iterates through the provided commands in the data.
- It directly calls methods in
Updraft_Smush_Manager_Commandsbased on the input. - Critical Failure: There is no check for
manage_optionscapability or a specific WP-Optimize nonce inside this specific Heartbeat flow.
- The function checks if
- Sink: The call reaches
Updraft_Smush_Manager_Commands::update_smush_options(), which updates theupdraft_smush_optionsrow in thewp_optionstable.
4. Nonce Acquisition Strategy
The WordPress Heartbeat API requires a standard WordPress Heartbeat nonce. This nonce is available to all logged-in users.
- Access Site: Use a Subscriber-level user to log in.
- Retrieve Nonce: Navigate to any admin page (e.g.,
/wp-admin/profile.php). The Heartbeat nonce is localized by WordPress core. - Browser Eval:
// The Heartbeat nonce is typically stored in the heartbeatSettings object window.heartbeatSettings?.nonce - Verification: Confirm the nonce is a 10-character hexadecimal string.
5. Exploitation Strategy
Goal: Unauthorized Modification of Plugin Settings
We will attempt to disable image backups using the update_smush_options command.
- Preparation: Log in as a Subscriber.
- Identify Target Command:
update_smush_options. - Construct Payload:
The Heartbeat request expects adataparameter containing a JSON object or array.action:heartbeatscreen_id:profile(or any valid admin screen)_nonce: [Heartbeat Nonce]data[wp-optimize][smush][command]:update_smush_optionsdata[wp-optimize][smush][data][options]: A JSON object representing the new settings (e.g., settingbackuptofalse).
Request Construction (using http_request)
POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=heartbeat&screen_id=profile&_nonce=[NONCE]&data%5Bwp-optimize%5D%5Bsmush%5D%5Bcommand%5D=update_smush_options&data%5Bwp-optimize%5D%5Bsmush%5D%5Bdata%5D%5Boptions%5D%5Bbackup%5D=0
Note: The exact structure of the data array may require slight adjustment based on how the plugin parses the nested array in receive_heartbeat().
6. Test Data Setup
- Install WP-Optimize: Ensure version 4.5.0 is installed.
- Configure Smush: Ensure Smush is enabled in the admin settings.
- Verify Current State: Run
wp option get updraft_smush_optionsand note thatbackupis likely1(true). - Create Attacker:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123.
7. Expected Results
- Response: The HTTP response will be a JSON object containing Heartbeat data. If successful, it might include a confirmation from the Smush command class within the
wp-optimizekey. - Side Effect: The
updraft_smush_optionsentry in the database will be modified.
8. Verification Steps
- Check Options via CLI:
Verify that thewp option get updraft_smush_options --format=jsonbackupfield (or the target field used in the payload) has changed from its original value to0. - Check Logs (Optional):
Attempt to use the same method with theget_smush_logscommand to see if logs are returned in the Heartbeat response:data[wp-optimize][smush][command]=get_smush_logs
9. Alternative Approaches
If update_smush_options requires a more complex payload, try clean_all_backup_images. This command is often a simple string without additional data parameters.
Payload for Backup Deletion:
data[wp-optimize][smush][command]:clean_all_backup_images
Verification for Backup Deletion:
- Upload an image and smush it so a backup is created in
wp-content/uploads/wpo-plugins-tables-list.jsonor the relevant backup directory. - Run the exploit.
- Check if the backup files or the backup record is removed.
Summary
WP-Optimize versions up to 4.5.0 lack proper authorization and nonce checks within the Heartbeat API handler in `includes/class-wp-optimize-heartbeat.php`. This allows authenticated users with Subscriber-level permissions or higher to execute administrative Smush commands, enabling them to modify plugin settings, delete image backups, and view logs.
Security Fix
@@ -1,5 +1,25 @@ == Changelog == += 4.5.1 - 23/Mar/2026 = + +* FIX: Fixed compatibility issue with WP Remote +* FIX: Notice: Function _load_textdomain_just_in_time was called incorrectly +* FIX: Resolved weekly cron not running on WordPress < 5.4 by switching to the wpo_weekly schedule +* FIX: Database table error when upgrading from free to premium version +* REFACTOR: Improved WebP conversion flow by separating capability checks from configuration changes +* REFACTOR: Improved auto-optimization handling by correcting static method usage +* REFACTOR: Introduced `WP_Optimize_Server_Compatibility` class to centralize all server environment checks +* REFACTOR: Removed separate `get_schedule_types()` method in premium version +* SECURITY: Enforced capability checks and allowed-command validation for Smush actions triggered via Heartbeat API. Thanks to WordFence for the responsible disclosure +* TWEAK: Display the `Enable the caching menu in the admin bar` option only when Cache or Minify is enabled +* TWEAK: Improved detection of LearnDash plugin tables +* TWEAK: Improved onboarding wizard RTL support and eliminated dependency on the PHP Reflection class +* TWEAK: Improved robustness of `uploads/wpo` directory removal during plugin uninstallation +* TWEAK: Minify - Don't remove the version query argument when the source is not processed by Minify +* TWEAK: Premium - Unused Images - Enhanced detection of edited WordPress images +* TWEAK: Prevent deprecation notices in PHP 8.5 +* TWEAK: Add a notice when `.htaccess` file is not available or renamed in Apache servers + = 4.5.0 - 11/Feb/2026 = * FEATURE: Premium - Cache – Added ability to cache only selected URLs
Exploit Outline
An attacker with Subscriber-level access can exploit this by intercepting or generating a WordPress Heartbeat API request. By sending a POST request to `/wp-admin/admin-ajax.php` with the `action` parameter set to `heartbeat` and a valid Heartbeat nonce, the attacker can include a `data[wp-optimize]` payload. This payload targets the Smush command processor (e.g., setting `data[wp-optimize][smush][command]` to `update_smush_options`) to modify plugin configurations or `clean_all_backup_images` to delete data. Because the `receive_heartbeat()` function fails to verify user capabilities (e.g., `manage_options`) before invoking the Smush command class, the request is processed with administrative privileges.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.