CVE-2025-68024

Addonify – WooCommerce Wishlist <= 2.0.15 - Missing Authorization to Unauthenticated Settings Update

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
2.0.16
Patched in
22d
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=2.0.15
PublishedFebruary 4, 2026
Last updatedFebruary 25, 2026
Affected pluginaddonify-wishlist

Source Code

WordPress.org SVN
Research Plan
Unverified

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 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) and nonce.
  • 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)

  1. Entry Point: The plugin registers AJAX hooks in a class (likely includes/admin/class-settings.php or includes/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
    
  2. Handler Function: The save_settings function is invoked.
  3. Security Check (Missing): The function may call check_ajax_referer('addonify_wishlist_nonce_action', 'nonce') but fails to call current_user_can('manage_options').
  4. Data Processing: The function iterates through $_POST['settings'].
  5. 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.

  1. Identify the Script Handle: The plugin likely uses addonify-wishlist-settings or addonify-wishlist-common.
  2. Identify the Localization Object: Search for wp_localize_script. The object is likely addonify_wishlist_params or addonify_wishlist_obj.
  3. 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") or browser_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.

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:

  1. Grep for Action: Run grep -r "wp_ajax_nopriv_addonify_wishlist_save_settings" . to confirm the exact action name.
  2. Verify Sink: Run grep -A 20 "function save_settings" . to see which option name is being updated (e.g., addonify_wishlist_options).
  3. Obtain Nonce: Use the browser_eval method described in Section 4.
  4. Send Exploit: Use http_request to send the malicious POST payload.

6. Test Data Setup

  1. Install Plugin: Ensure addonify-wishlist version 2.0.15 is installed.
  2. Create Trigger Page:
    wp post create --post_type=page --post_title="Wishlist Test" --post_status=publish --post_content='[addonify_wishlist]'
    
  3. Identify Baseline:
    wp option get addonify_wishlist_settings
    

7. Expected Results

  • HTTP Response: A successful response (e.g., {"success":true} or 1).
  • Database Change: The WordPress option addonify_wishlist_settings (or similar) will be updated with the attacker-supplied values.

8. Verification Steps

  1. Check Options via CLI:
    wp option get addonify_wishlist_settings
    
    Confirm that wishlist_button_text is now HACKED_BY_AGENT.
  2. Verify Frontend:
    Navigate to the shop page and check if the wishlist button text has changed.

9. Alternative Approaches

  • If settings expects JSON: Try sending settings={"wishlist_button_text":"HACKED"}.
  • Missing Nonce: If check_ajax_referer is not called at all, omit the nonce parameter entirely.
  • Option Overwrite: If the code uses update_option( $_POST['option_name'], ... ) without strict validation, this could escalate to a full site takeover by overwriting default_role or users_can_register. (Check the code for $wpdb or update_option calls with dynamic keys).
Research Findings
Static analysis — not yet PoC-verified

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

--- a/includes/admin/class-settings.php
+++ b/includes/admin/class-settings.php
@@ -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.