CVE-2025-15520

RegistrationMagic – Custom Registration Forms, User Registration, Payment, and User Login <= 6.0.7.1 - Authenticated (Subscriber+) Information Exposure

mediumExposure of Sensitive Information to an Unauthorized Actor
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
6.0.7.2
Patched in
102d
Time to patch

Description

The RegistrationMagic – Custom Registration Forms, User Registration, Payment, and User Login plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 6.0.7.1. This makes it possible for authenticated attackers, with Subscriber-level access and above, to extract sensitive user or configuration data.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=6.0.7.1
PublishedJanuary 23, 2026
Last updatedMay 4, 2026

What Changed in the Fix

Changes introduced in v6.0.7.2

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

vars.nonce`. Wait, I see a huge potential leak: `admin/controllers/class_rm_form_controller.php`: ```php $data[$i]->form_attachments = $attach_service->get_all_form_attachments($form->form_id); ``` This lists all files uploaded to a form. Let's formulate the plan: T…

Show full research plan

vars.nonce`.

Wait, I see a huge potential leak:
`admin/controllers/class_rm_form_controller.php`:
```php
$data[$i]->form_attachments = $attach_service->get_all_form_attachments($form->form_id);
```
This lists all files uploaded to a form.

Let's formulate the plan:
The vulnerability allows any authenticated user (Subscriber+) to access admin-only controllers by leveraging the `rm_get_stats` AJAX action (or other actions mapped to `RM_Main_Controller::run`) and specifying a privileged `rm_slug`.

Wait, I'll bet the `rm_ajax_secure` nonce is *not even checked* for `rm_get_stats`.
Many RM vulnerabilities in 2024/2025 involve `run()` not checking nonces or permissions correctly.

1.  Login as Subscriber.
2.  Request `admin-ajax.php?action=rm_get_stats&rm_slug=rm_user_manage`.
3.  Check if it returns the user manager HTML.
4.  If it needs a nonce, try to find one. (Check `wp-admin` dashboard for any localized RM nonces).

Wait, looking at `class_rm_admin.php` again:
`$this->icon = base64_encode('<svg ...');`
Nothing there.
Research Findings
Static analysis — not yet PoC-verified

Summary

RegistrationMagic for WordPress is vulnerable to sensitive information exposure because several administrative controller actions and views lack proper authorization and nonce checks. Authenticated users with Subscriber-level privileges can invoke these actions—such as retrieving additional user details or accessing form attachment lists—by directly interacting with the plugin's controller routing system.

Vulnerable Code

// admin/controllers/class_rm_user_controller.php line 428-440
public function additional_details($model, RM_User_Services $service, $request, $params){
    $user_details = array();
    //if(check_ajax_referer('rm_ajax_secure','rm_sec_nonce')) {
        if(!empty($request->req['user_ids'])){
            $user_ids = $request->req['user_ids'];
            $user_details = $service->user_additional_details($user_ids);
        }
    //}
    wp_send_json_success($user_details);
    die();
    
}

---

// admin/controllers/class_rm_form_controller.php line 292-311
public function quick_add($model, $service, $request, $params) {
    $valid = false;
    if ($this->mv_handler->validateForm("rm_form_quick_add")) {
        $model->set($request->req);

        $valid = $model->validate_model();
    }
    if ($valid) {
        //By default make it registration type
        $model->set_form_type(1);
        $model->set_default_form_user_role('subscriber');

        if (isset($request->req['form_id']))
            $valid = $service->update($request->req['form_id']);
        else
            $service->add_user_form();
    }

    $this->manage($model, $service, $request, $params);
}

---

// admin/class_rm_admin.php line 487-495
if (in_array( $role_slug, $value[2] )){

    if ( ! $rm_role->has_cap( $value[0]."manage_options" ) ) {

        $rm_role->add_cap( $value[0]."manage_options" );

        $role_added = true;

    }
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/custom-registration-form-builder-with-submission-manager/6.0.7.1/admin/class_rm_admin.php /home/deploy/wp-safety.org/data/plugin-versions/custom-registration-form-builder-with-submission-manager/6.0.7.2/admin/class_rm_admin.php
--- /home/deploy/wp-safety.org/data/plugin-versions/custom-registration-form-builder-with-submission-manager/6.0.7.1/admin/class_rm_admin.php	2026-01-05 07:43:00.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/custom-registration-form-builder-with-submission-manager/6.0.7.2/admin/class_rm_admin.php	2026-01-16 07:46:28.000000000 +0000
@@ -477,7 +477,6 @@
                 $admin_order = $gopts->get_value_of('enable_admin_order') == 'yes' ? $gopts->get_value_of('admin_order') : $gopts->default['admin_order'];
                 $admin_order = apply_filters('rm_admin_menu_order_list',$admin_order, $gopts);
                 $role_top_admin = array("administrator");
-
                 foreach ($admin_order as $value) {
 
                     foreach ( $roles as $role_slug => $role ) {
@@ -485,8 +484,7 @@
                         $rm_role = get_role( $role_slug );
 
                         if (in_array( $role_slug, $value[2] )){
-
-                            if ( ! $rm_role->has_cap( $value[0]."manage_options" ) ) {
+                            if ( ! $rm_role->has_cap( $value[0]."manage_options" ) && !empty(trim($value[0])) ) {
 
                                 $rm_role->add_cap( $value[0]."manage_options" );
 
@@ -805,7 +803,7 @@
 
                             } elseif ($value[0] == 'rm_subscriptions') {
                                 // attachments menu
-                                do_action("rm_admin_menu_after_automation",$value[0]);
+                                do_action("rm_admin_menu_after_automation",$value[0], $value[3]);
                                 
                             } elseif ($value[0] == 'rm_analytics_show_form') {
 
@@ -1125,6 +1123,10 @@
 
                                     // do_action("rm_admin_menu_after_field_stats","");
 
+                                }  elseif ($value[0] == 'rm_subscriptions') {
+                                    // attachments menu
+                                    do_action("rm_admin_menu_after_automation",$value[0], $value[3]);
+                                
                                 } elseif ($value[0] == 'rm_analytics_show_form') {
 
                                     // Analytics > FORMS
@@ -1174,7 +1176,7 @@
 
                                     // setting
 
-                                    add_submenu_page("rm_form_manage", RM_UI_Strings::get('ADMIN_MENU_SETTINGS'), RM_UI_Strings::get('ADMIN_MENU_SETTINGS'), "manage_options", "rm_options_manage", array($this->get_controller(), 'run'));
+                                    add_submenu_page(current_user_can('manage_options') ? "rm_form_manage" : "rm_dummy_string", RM_UI_Strings::get('ADMIN_MENU_SETTINGS'), RM_UI_Strings::get('ADMIN_MENU_SETTINGS'), "manage_options", "rm_options_manage", array($this->get_controller(), 'run'));
 
                                     // setting options
 
@@ -290,24 +290,26 @@
     }
 
     public function quick_add($model, $service, $request, $params) {
-        $valid = false;
-        if ($this->mv_handler->validateForm("rm_form_quick_add")) {
-            $model->set($request->req);
+        if (current_user_can('manage_options') || current_user_can('rm_form_managemanage_options')) {
+            $valid = false;
+            if ($this->mv_handler->validateForm("rm_form_quick_add")) {
+                $model->set($request->req);
 
-            $valid = $model->validate_model();
-        }
-        if ($valid) {
-            //By default make it registration type
-            $model->set_form_type(1);
-            $model->set_default_form_user_role('subscriber');
+                $valid = $model->validate_model();
+            }
+            if ($valid) {
+                //By default make it registration type
+                $model->set_form_type(1);
+                $model->set_default_form_user_role('subscriber');
 
-            if (isset($request->req['form_id']))
-                $valid = $service->update($request->req['form_id']);
-            else
-                $service->add_user_form();
-        }
+                if (isset($request->req['form_id']))
+                    $valid = $service->update($request->req['form_id']);
+                else
+                    $service->add_user_form();
+            }
 
-        $this->manage($model, $service, $request, $params);
+            $this->manage($model, $service, $request, $params);
+        }
     }
 
     public function import($model, $service, $request, $params) {
@@ -560,7 +560,7 @@
         
     }
     public function admin_menu($model, RM_Setting_Service $service, $request, $params){
-        if ($this->mv_handler->validateForm("options_admin_menu")){
+        if ($this->mv_handler->validateForm("options_admin_menu") && current_user_can('manage_options')) {
             if ($request->req['restore'] == 'false'){
                 $options = array();
                 $options['admin_order'] = "";
@@ -428,17 +428,15 @@
         $this->manage($model,$service,$request,$params);
     }
     
-    public function additional_details($model, RM_User_Services $service, $request, $params){
-        $user_details = array();
-        //if(check_ajax_referer('rm_ajax_secure','rm_sec_nonce')) {
-            if(!empty($request->req['user_ids'])){
+    public function additional_details($model, RM_User_Services $service, $request, $params) {
+        if(check_ajax_referer('rm_ajax_secure','rm_sec_nonce') && (current_user_can('manage_options') || current_user_can('rm_user_managemanage_options'))) {
+            $user_details = array();
+            if(!empty($request->req['user_ids'])) {
                 $user_ids = $request->req['user_ids'];
                 $user_details = $service->user_additional_details($user_ids);
             }
-        //}
-        wp_send_json_success($user_details);
-        die();
-        
+            wp_send_json_success($user_details);
+        }
     }

Exploit Outline

An authenticated attacker with Subscriber-level privileges can exploit this vulnerability by directly calling administrative actions registered through the plugin's `RM_Main_Controller::run` router. Specifically, the attacker can use the `rm_get_stats` AJAX action (intended for admins) and provide a privileged `rm_slug` (e.g., `rm_user_manage`) along with the target action (e.g., `additional_details`). Because the vulnerable functions lacked permission checks and sometimes bypassed nonce verification, the attacker can retrieve sensitive user profile data by supplying a list of `user_ids` in the request, or perform other unauthorized actions like creating/modifying forms via `quick_add`.

Check if your site is affected.

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