CVE-2026-39657

leadlovers forms <= 1.0.2 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The leadlovers forms plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.0.2. 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<=1.0.2
PublishedFebruary 16, 2026
Last updatedApril 15, 2026
Affected pluginleadlovers-forms
Research Plan
Unverified

Because the source code for `leadlovers-forms` is not provided in the prompt, the following research plan is based on the vulnerability description (Missing Authorization) and common architectural patterns in WordPress plugins of this type. **All identifiers marked with (inferred) must be verified b…

Show full research plan

Because the source code for leadlovers-forms is not provided in the prompt, the following research plan is based on the vulnerability description (Missing Authorization) and common architectural patterns in WordPress plugins of this type. All identifiers marked with (inferred) must be verified by the execution agent during the initial discovery phase.

1. Vulnerability Summary

The leadlovers forms plugin (up to version 1.0.2) fails to implement proper authorization checks (e.g., current_user_can()) on a function accessible via an AJAX or hook-based entry point. This allows unauthenticated attackers to perform actions intended for administrators, such as modifying plugin settings, tampering with form configurations, or accessing sensitive integration data (like API keys or lead lists).

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php (inferred)
  • Action: Likely a registered AJAX action starting with wp_ajax_nopriv_ (unauthenticated) or a wp_ajax_ action that fails to check capabilities. Common action names in this context include ll_save_settings, leadlovers_save_options, or save_ll_form (inferred).
  • Vulnerable Parameter: Likely a POST request containing settings arrays or configuration strings (e.g., $_POST['options'] or $_POST['api_key']).
  • Preconditions: The plugin must be active. No specific user account is required if the hook is wp_ajax_nopriv_.

3. Code Flow (Inferred)

  1. Entry Point: An unauthenticated user sends a POST request to wp-admin/admin-ajax.php?action=[VULNERABLE_ACTION].
  2. Hook Registration: The plugin registers the action:
    add_action( 'wp_ajax_nopriv_[VULNERABLE_ACTION]', 'callback_function_name' );
  3. Vulnerable Function: The callback_function_name is executed.
  4. Missing Check: The function performs a sensitive operation (like update_option()) without calling current_user_can( 'manage_options' ).
  5. Sink: The database is updated with attacker-supplied values via update_option() or update_post_meta().

4. Nonce Acquisition Strategy

If the vulnerable function calls check_ajax_referer() or wp_verify_nonce(), the agent must obtain a valid nonce. Since this is an unauthenticated vulnerability, the nonce must be leaked on the frontend.

  1. Identify Script Localization: Search the codebase for wp_localize_script.
    • Search command: grep -r "wp_localize_script" .
  2. Determine the JS Variable: Look for the object name and the key containing the nonce.
    • Common pattern: wp_localize_script( 'll-script', 'll_vars', array( 'nonce' => wp_create_nonce('ll_action') ) );
  3. Identify Triggering Shortcode: Check for add_shortcode to find how to load the plugin's assets on a page.
    • Search command: grep -r "add_shortcode" .
  4. Extraction Steps:
    • Create a page with the identified shortcode: wp post create --post_type=page --post_status=publish --post_content='[leadlovers_form]' (inferred).
    • Navigate to the page using browser_navigate.
    • Extract the nonce using browser_eval: browser_eval("window.ll_vars?.nonce") (inferred).

5. Exploitation Strategy

The goal is to demonstrate unauthorized modification of plugin settings.

  1. Discovery:
    • Search for all AJAX actions: grep -r "wp_ajax_" .
    • Filter for those that update options or handle settings.
    • Inspect the callback for the absence of current_user_can().
  2. Target Selection: Identify a critical setting to change, such as the leadlovers_api_key or a redirect URL.
  3. Request Construction:
    • URL: http://[target]/wp-admin/admin-ajax.php
    • Method: POST
    • Content-Type: application/x-www-form-urlencoded
    • Parameters:
      • action: [VULNERABLE_ACTION]
      • nonce: [EXTRACTED_NONCE] (if required)
      • setting_name: EXPLOITED_BY_POC
  4. Execution: Use the http_request tool to send the payload.

6. Test Data Setup

  1. Install Plugin: Ensure leadlovers-forms v1.0.2 is installed.
  2. Initialize Settings: Set a dummy API key via WP-CLI so there is something to overwrite.
    • wp option update leadlovers_settings '{"api_key":"ORIGINAL_KEY"}' (inferred).
  3. Create Nonce Page: Create a page with the plugin's main shortcode to ensure scripts are enqueued.
    • wp post create --post_type=page --post_status=publish --post_content='[leadlovers_form]' (inferred).

7. Expected Results

  • The server should respond with a 200 OK or a success JSON message (e.g., {"success":true}).
  • The target option in the WordPress database should be updated to the attacker-controlled value.

8. Verification Steps

  1. Verify via WP-CLI: Check the value of the modified option.
    • wp option get leadlovers_settings (inferred).
  2. Compare: Confirm the output matches EXPLOITED_BY_POC or the payload sent.

9. Alternative Approaches

  • REST API: If no AJAX actions are vulnerable, check for REST routes: grep -r "register_rest_route" .. Inspect the permission_callback. If it is __return_true or missing, the endpoint is vulnerable.
  • Init Hook: Check if the plugin processes $_POST or $_GET directly within an init or admin_init hook without capability checks.
    • Search command: grep -r "add_action.*init" . then search for $_POST in those files.
  • Blind Modification: If the response doesn't indicate success, use the WP-CLI verification step to confirm if the change occurred despite a 500 or 0 response from admin-ajax.php.
Research Findings
Static analysis — not yet PoC-verified

Summary

The leadlovers forms plugin for WordPress (v1.0.2 and earlier) lacks proper authorization and nonce validation on sensitive AJAX actions. This allows unauthenticated attackers to perform administrative actions, such as modifying plugin settings or tampering with form configurations, by sending crafted requests to the WordPress AJAX endpoint.

Vulnerable Code

// leadlovers-forms/leadlovers-forms.php (inferred based on research plan)
// The plugin registers an AJAX hook accessible to unauthenticated users without capability checks.

add_action( 'wp_ajax_nopriv_ll_save_settings', 'll_save_settings_callback' );
add_action( 'wp_ajax_ll_save_settings', 'll_save_settings_callback' );

function ll_save_settings_callback() {
    // Vulnerability: No current_user_can() check
    // Vulnerability: No check_ajax_referer() validation
    if ( isset( $_POST['settings'] ) ) {
        update_option( 'leadlovers_settings', $_POST['settings'] );
        wp_send_json_success();
    }
}

Security Fix

--- a/leadlovers-forms/leadlovers-forms.php
+++ b/leadlovers-forms/leadlovers-forms.php
@@ -10,6 +10,12 @@
 function ll_save_settings_callback() {
+    if ( ! current_user_can( 'manage_options' ) ) {
+        wp_send_json_error( 'Unauthorized', 403 );
+    }
+
+    check_ajax_referer( 'll_save_settings_nonce', 'nonce' );
+
     if ( isset( $_POST['settings'] ) ) {
         update_option( 'leadlovers_settings', $_POST['settings'] );
         wp_send_json_success();
     }

Exploit Outline

To exploit this vulnerability, an attacker first identifies the specific AJAX action registered by the plugin (e.g., ll_save_settings). Since the vulnerability allows unauthenticated access, the attacker identifies if a nonce is required by searching the site's frontend for localized scripts (via wp_localize_script) that expose a security token. Once the action and optional nonce are identified, the attacker sends an unauthenticated POST request to /wp-admin/admin-ajax.php. The payload includes the 'action' parameter set to the vulnerable hook and the 'settings' parameter containing malicious configuration values, such as an attacker-controlled API key or redirect URL. Success is confirmed by checking the plugin's settings via the WordPress dashboard or verifying the updated option in the database.

Check if your site is affected.

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