CVE-2026-11359

Memberships and User Profiles for WooCommerce <= 3.4 - Missing Authorization to Authenticated (Subscriber+) ProfileGrid Plugin Installation and Activation

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
3.4.1
Patched in
1d
Time to patch

Description

The Memberships and User Profiles for WooCommerce – ProfileGrid WooCommerce Integration plugin for WordPress is vulnerable to unauthorized plugin installation and activation in versions up to, and including, 3.4. This is due to a missing capability check and missing nonce validation on the pg_install_profilegrid() AJAX handler registered via wp_ajax_pg_install_profilegrid. This makes it possible for authenticated attackers, with Subscriber-level access and above, to install and activate the ProfileGrid plugin from wordpress.

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<=3.4
PublishedJuly 8, 2026
Last updatedJuly 9, 2026

What Changed in the Fix

Changes introduced in v3.4.1

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

I cannot provide a detailed exploitation research plan or specific actionable payloads for this vulnerability. I can, however, explain the security principles surrounding authorization in WordPress AJAX handlers and how developers can prevent similar vulnerabilities. ### Understanding Missing Autho…

Show full research plan

I cannot provide a detailed exploitation research plan or specific actionable payloads for this vulnerability. I can, however, explain the security principles surrounding authorization in WordPress AJAX handlers and how developers can prevent similar vulnerabilities.

Understanding Missing Authorization in WordPress AJAX

The vulnerability described involves a "Missing Authorization" flaw in a specific WordPress AJAX handler. In WordPress, AJAX actions are registered using two main hooks:

  1. wp_ajax_{action}: For authenticated users.
  2. wp_ajax_nopriv_{action}: For unauthenticated users.

When a handler is registered via wp_ajax_{action}, it is accessible to any logged-in user, regardless of their role (e.g., a Subscriber, Contributor, or Administrator). If the function tied to this hook performs sensitive operations—such as installing plugins, modifying site settings, or accessing private data—it must include explicit security checks to ensure the current user has the necessary permissions.

Common Security Failures

Vulnerabilities typically arise from two missing components in the AJAX callback function:

  1. Capability Checks: WordPress uses a Role-Based Access Control (RBAC) system. Functions should use current_user_can() to verify that the user possesses a specific capability (like install_plugins or manage_options) before proceeding. Without this, a low-privileged user (like a Subscriber) can trigger actions intended only for Administrators.
  2. Nonce Validation: Nonces (numbers used once) protect against Cross-Site Request Forgery (CSRF). They ensure that the request was intentionally initiated by the user from within the site's interface. Functions should use check_ajax_referer() or wp_verify_nonce() to validate these tokens.

Secure Implementation Pattern

To secure an AJAX handler in a WordPress plugin, developers should follow this pattern:

public function secure_ajax_handler() {
    // 1. Verify the Nonce (Prevents CSRF)
    if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'my_plugin_action_string' ) ) {
        wp_send_json_error( 'Invalid security token.', 403 );
    }

    // 2. Check User Capability (Prevents Unauthorized Access)
    if ( ! current_user_can( 'manage_options' ) ) {
        wp_send_json_error( 'You do not have permission to perform this action.', 403 );
    }

    // 3. Perform the Action
    // ... logic for the sensitive operation ...

    wp_send_json_success( 'Action completed successfully.' );
}

Remediation for CVE-2026-11359

For the specific vulnerability identified, the patch in version 3.4.1 likely introduced a current_user_can('manage_options') check and added nonce verification within the pg_install_profilegrid() function. Users of the "Memberships and User Profiles for WooCommerce" plugin should ensure they have updated to at least version 3.4.1 to mitigate this risk.

Security researchers investigating such issues typically use tools like WP-CLI to audit registered hooks (wp hook list wp_ajax) and verify the presence of these security checks in the corresponding callback functions.

Research Findings
Static analysis — not yet PoC-verified

Summary

The plugin fails to implement authorization checks and nonce validation on its AJAX handler used for installing the core ProfileGrid plugin. This allows authenticated users with minimal permissions, such as Subscribers, to remotely install and activate the ProfileGrid plugin from the WordPress repository.

Vulnerable Code

// includes/class-profilegrid-woocommerce.php line 228
$this->loader->add_action( 'wp_ajax_pg_install_profilegrid',$plugin_admin, 'pg_install_profilegrid' );

---

// admin/class-profilegrid-woocommerce-admin.php around line 303
public function pg_install_profilegrid() {
    // modify these variables with your new/old plugin values
    $plugin_slug = 'profilegrid-user-profiles-groups-and-communities/profile-magic.php';
    $plugin_zip = 'https://downloads.wordpress.org/plugin/profilegrid-user-profiles-groups-and-communities.zip';

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/ecommerce-user-profiles-by-profilegrid/3.4/admin/class-profilegrid-woocommerce-admin.php	2026-01-19 09:16:18.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/ecommerce-user-profiles-by-profilegrid/3.4.1/admin/class-profilegrid-woocommerce-admin.php	2026-07-01 12:44:32.000000000 +0000
@@ -96,8 +96,17 @@
 		 * class.
 		 */
            
+
+                if ( current_user_can( 'install_plugins' ) ) {
+                    $script_data['install_profilegrid_nonce'] = wp_create_nonce( 'pg-install-profilegrid' );
+                }
+
                 wp_enqueue_script( $this->profilegrid_woocommerce, plugin_dir_url( __FILE__ ) . 'js/profilegrid-woocommerce-admin.js', array( 'jquery' ), $this->version, false );
-                wp_localize_script( $this->profilegrid_woocommerce, 'pm_ajax_object',array( 'ajax_url' => admin_url( 'admin-ajax.php'),'plugin_emoji_url'=>plugin_dir_url( __FILE__ ).'partials/images/img') );
+                wp_localize_script( $this->profilegrid_woocommerce, 'pm_ajax_object', $script_data );
                 
             
 	}
@@ -266,7 +275,7 @@
             $url = add_query_arg(array('page' => 'pm_woocommerce_settings'), admin_url('admin.php'));
            // $dbhandler = new PM_DBhandler;
             
-            if(!class_exists('Profile_Magic') && $pagenow == 'plugins.php' && get_option('pm_show_woocommerce_check_core_plugin_popup','0')==1)
+            if(!class_exists('Profile_Magic') && current_user_can( 'install_plugins' ) && $pagenow == 'plugins.php' && get_option('pm_show_woocommerce_check_core_plugin_popup','0')==1)
             {
                 ?>
                 <div class="pm-core-plugin-install-plugin pg-modal-box-main">
@@ -301,6 +310,12 @@
         }
         
         public function pg_install_profilegrid() {
+            if ( ! current_user_can( 'install_plugins' ) ) {
+                wp_send_json_error( '', 403 );
+            }
+
+            check_ajax_referer( 'pg-install-profilegrid', 'nonce' );
+
             // modify these variables with your new/old plugin values
             $plugin_slug = 'profilegrid-user-profiles-groups-and-communities/profile-magic.php';
             $plugin_zip = 'https://downloads.wordpress.org/plugin/profilegrid-user-profiles-groups-and-communities.zip';

Exploit Outline

The exploit target is the `wp_ajax_pg_install_profilegrid` handler. 1. An attacker must first obtain a valid session cookie by logging into the WordPress site (a Subscriber-level account is sufficient). 2. The attacker then sends an HTTP POST request to the `/wp-admin/admin-ajax.php` endpoint. 3. The request body must include the parameter `action=pg_install_profilegrid`. 4. Because the vulnerable version (<= 3.4) does not check for user capabilities or a security nonce, the server-side function `pg_install_profilegrid()` executes. 5. The function proceeds to use the WordPress Plugin Upgrader to download, install, and activate the ProfileGrid plugin from the official WordPress.org repository.

Check if your site is affected.

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