[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fu2MXGGc-FaYzQ5m0SRlWNdkbnmNZ2opqan6OGaSjdf4":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":9,"research_fix_diff":35,"research_exploit_outline":36,"research_model_used":37,"research_started_at":38,"research_completed_at":39,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":40},"CVE-2026-4609","profilegrid-missing-authorization-to-authenticated-subscriber-arbitrary-group-joining","ProfileGrid \u003C= 5.9.8.4 - Missing Authorization to Authenticated (Subscriber+) Arbitrary Group Joining","The ProfileGrid – User Profiles, Groups and Communities plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on the pm_invite_user function in all versions up to, and including, 5.9.8.4. This makes it possible for authenticated attackers, with Subscriber-level access and above, to add themselves or any registered user to any ProfileGrid group, including closed and paid groups, bypassing all authorization and payment gates.","profilegrid-user-profiles-groups-and-communities",null,"\u003C=5.9.8.4","5.9.8.5","high",7.1,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:L\u002FI:H\u002FA:N","Missing Authorization","2026-05-12 00:00:00","2026-05-13 13:27:58",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fc3678b4d-0cd0-4873-8cf3-90c557931f4c?source=api-prod",2,[22,23,24,25,26,27,28,29],"admin\u002Fclass-profile-magic-admin.php","admin\u002Fjs\u002Fprofile-magic-admin-footer.js","admin\u002Fjs\u002Fprofile-magic-admin.js","admin\u002Fpartials\u002Fadd-group-tabview.php","includes\u002Fclass-profile-magic-chat-system.php","includes\u002Fclass-profile-magic-dbhandler.php","includes\u002Fclass-profile-magic-messenger.php","includes\u002Fclass-profile-magic-request.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-4609 (ProfileGrid Group Joining Bypass)\n\n## 1. Vulnerability Summary\nThe **ProfileGrid** plugin for WordPress (up to and including version 5.9.8.4) contains a missing authorization vulnerability in the `pm_invite_user` function. While this function is intended to allow group managers or administrators to invite users to groups, it lacks the necessary capability checks. This allows any authenticated user (starting from the **Subscriber** role) to invoke this function via an AJAX request to add themselves or any other user to any group, effectively bypassing \"Closed\" group restrictions and \"Paid\" group payment gates.\n\n## 2. Attack Vector Analysis\n- **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Action**: `pm_invite_user`\n- **HTTP Method**: `POST`\n- **Authentication**: Authenticated (Subscriber or above)\n- **Vulnerable Parameter(s)**: \n    - `group_id`: The ID of the target ProfileGrid group.\n    - `user_id`: The ID of the user to be added (can be the attacker's own ID).\n- **Preconditions**:\n    - The attacker must be logged in as a Subscriber.\n    - The target group ID must be known (groups are often listed on the frontend).\n\n## 3. Code Flow (Inferred)\n1. **Entry Point**: The AJAX action `wp_ajax_pm_invite_user` (and potentially `wp_ajax_nopriv_pm_invite_user` depending on the implementation, though the CVE specifies \"Authenticated\") is registered in the plugin initialization.\n2. **Handler**: The request is routed to the `pm_invite_user` function (typically located in the `PM_request` class or a dedicated AJAX handler class).\n3. **Missing Check**: The function likely calls `check_ajax_referer()` to verify a nonce but fails to verify if the `current_user_id()` has permission to manage the group specified by `group_id` or invite users generally (e.g., `current_user_can('manage_options')`).\n4. **Sink**: The function uses the `PM_DBhandler` (visible in `includes\u002Fclass-profile-magic-dbhandler.php`) or `update_user_meta` to associate the `user_id` with the `group_id` in the `pm_group` meta key (as seen in the logic within `admin\u002Fpartials\u002Fadd-group-tabview.php`).\n\n## 4. Nonce Acquisition Strategy\nProfileGrid typically enqueues nonces for its AJAX actions via `wp_localize_script`. Since `pm_invite_user` is a frontend-facing feature for group managers, the nonce is likely available on group pages or the user's profile.\n\n**Strategy**:\n1. Identify a page where ProfileGrid scripts are loaded (e.g., a page containing the `[pg_groups]` or `[pg_group_members]` shortcode).\n2. Use the `browser_eval` tool to extract the nonce from the localized JavaScript objects.\n3. Common objects in ProfileGrid include `pg_ajax_object` or `pm_fields_object`.\n\n**Execution**:\n1. Create a dummy page with a ProfileGrid shortcode: `wp post create --post_type=page --post_status=publish --post_content='[pg_groups]'`.\n2. Navigate to that page as a Subscriber.\n3. Execute JavaScript to find the nonce:\n   ```javascript\n   \u002F\u002F Attempt to find the nonce in common ProfileGrid objects\n   window.pg_ajax_object?.ajax_nonce || window.pm_fields_object?.nonce\n   ```\n\n## 5. Exploitation Strategy\n### Step 1: Reconnaissance\n1. Create a \"Closed\" group as an Administrator and note its ID (e.g., `gid=2`).\n2. Create a \"Paid\" group as an Administrator and note its ID (e.g., `gid=3`).\n3. Identify the current Subscriber's user ID.\n\n### Step 2: Exploitation (Joining the Group)\nSubmit an AJAX request to add the Subscriber to the restricted group.\n\n**Request Details**:\n- **URL**: `http:\u002F\u002Ftarget.local\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Content-Type**: `application\u002Fx-www-form-urlencoded`\n- **Body**:\n  ```text\n  action=pm_invite_user&group_id=[TARGET_GID]&user_id=[SUBSCRIBER_UID]&_wpnonce=[EXTRACTED_NONCE]\n  ```\n\n### Step 3: Persistence\u002FSecondary Exploit\nOptionally, attempt to add the Administrator or another user to a group they shouldn't be in to verify \"Arbitrary User\" addition.\n\n## 6. Test Data Setup\n1. **Target Groups**:\n   ```bash\n   # Create a closed group via WP-CLI (simulating admin action)\n   # Note: gid is usually the primary key in the 'wp_pg_groups' table\n   wp eval \"global \\$wpdb; \\$wpdb->insert(\\$wpdb->prefix . 'pg_groups', ['group_name' => 'Secret Society', 'group_options' => serialize(['group_type' => 'Closed'])]);\"\n   ```\n2. **Victim\u002FAttacker User**:\n   ```bash\n   wp user create attacker attacker@example.com --role=subscriber --user_pass=password123\n   ```\n3. **Nonce Page**:\n   ```bash\n   wp post create --post_type=page --post_title=\"Groups\" --post_status=publish --post_content='[pg_groups]'\n   ```\n\n## 7. Expected Results\n- **Response**: The server should return a success message (often `1` or a JSON success status).\n- **Access**: The Subscriber user should now have access to the \"Closed\" group's content and appear in the group's member list.\n\n## 8. Verification Steps\n1. **Database Check**: Check the `pm_group` user meta for the attacker.\n   ```bash\n   wp user meta get [ATTACKER_UID] pm_group\n   ```\n   *Expected Outcome*: The meta value (usually a serialized array or string containing IDs) should now include the `[TARGET_GID]`.\n2. **UI Check**: Log in as the attacker and navigate to the group page to confirm content is visible without a \"Join Pending\" or \"Payment Required\" notice.\n\n## 9. Alternative Approaches\nIf `pm_invite_user` is not the correct action for self-joining, investigate:\n- `pm_join_group`: Often used for Open groups but may lack checks for Closed\u002FPaid groups in the vulnerable version.\n- Parameters: Some versions of ProfileGrid use `gid` instead of `group_id`. Verify parameter names by checking `admin\u002Fjs\u002Fprofile-magic-admin.js` for AJAX calls.","The ProfileGrid plugin for WordPress is vulnerable to unauthorized access due to a missing authorization check in the pm_invite_user AJAX action handler. Authenticated attackers with Subscriber-level access can exploit this to add themselves or any registered user to any ProfileGrid group, including private and paid groups, bypassing authorization and payment requirements.","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fprofilegrid-user-profiles-groups-and-communities\u002F5.9.8.4\u002Fadmin\u002Fclass-profile-magic-admin.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fprofilegrid-user-profiles-groups-and-communities\u002F5.9.8.5\u002Fadmin\u002Fclass-profile-magic-admin.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fprofilegrid-user-profiles-groups-and-communities\u002F5.9.8.4\u002Fadmin\u002Fclass-profile-magic-admin.php\t2026-03-12 09:28:08.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fprofilegrid-user-profiles-groups-and-communities\u002F5.9.8.5\u002Fadmin\u002Fclass-profile-magic-admin.php\t2026-03-26 10:46:24.000000000 +0000\n@@ -868,20 +868,33 @@\n \n \n \tpublic function profile_magic_set_field_order() {\n+\t\t$this->pg_validate_reorder_ajax_request();\n \t\tinclude 'partials\u002Fset-fields-order.php';\n \t\tdie;\n \t}\n \n \tpublic function profile_magic_set_group_order() {\n+\t\t$this->pg_validate_reorder_ajax_request();\n \t\tinclude 'partials\u002Fset-groups-order.php';\n \t\tdie;\n \t}\n \n \tpublic function profile_magic_set_group_items() {\n+\t\t$this->pg_validate_reorder_ajax_request();\n \t\tinclude 'partials\u002Fset-groups-order.php';\n \t\tdie;\n \t}\n \n+\tprivate function pg_validate_reorder_ajax_request() {\n+\t\tif ( ! current_user_can( 'manage_options' ) ) {\n+\t\t\twp_send_json_error( esc_html__( 'Unauthorized', 'profilegrid-user-profiles-groups-and-communities' ), 403 );\n+\t\t}\n+\n+\t\tif ( ! check_ajax_referer( 'ajax-nonce', 'nonce', false ) ) {\n+\t\t\twp_send_json_error( esc_html__( 'Failed security check', 'profilegrid-user-profiles-groups-and-communities' ), 403 );\n+\t\t}\n+\t}\n+\n \tpublic function profile_magic_set_section_order() {\n                 if ( !current_user_can('manage_options') ) {\n                     die;\n@@ -1876,6 +1889,15 @@\n \n         }\n \tpublic function pm_group_option_update() {\n+\t\t\u002F\u002F This option sync is only needed on normal wp-admin page loads.\n+\t\tif ( ! is_admin() || wp_doing_ajax() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {\n+\t\t\treturn;\n+\t\t}\n+\n+\t\tif ( ! class_exists( 'PM_DBhandler' ) || ! class_exists( 'PM_request' ) ) {\n+\t\t\treturn;\n+\t\t}\n+\n \t\t$dbhandler = new PM_DBhandler();\n \t\t$pmrequest = new PM_request();\n \n... (truncated at 18000 of 101674 chars — patch_diff)","The exploit targets the pm_invite_user AJAX action, which lacks capability checks for the requesting user. \n\n1. Authentication: The attacker logs in with at least Subscriber-level privileges.\n2. Target ID: The attacker identifies the group_id of a target group (e.g., a Restricted or Paid group) from the site's group directory or HTML source.\n3. Nonce Retrieval: The attacker extracts a valid AJAX nonce from the localized JavaScript objects pg_ajax_object or pm_fields_object, typically found on pages utilizing ProfileGrid shortcodes.\n4. Malicious Request: The attacker sends a POST request to \u002Fwp-admin\u002Fadmin-ajax.php using the following parameters:\n    - action: pm_invite_user\n    - group_id: [Target Group ID]\n    - user_id: [Attacker User ID or Victim User ID]\n    - _wpnonce: [Extracted Nonce]\n5. Verification: The server adds the user specified in user_id to the restricted group, granting access to protected content or memberships without payment or admin approval.","gemini-3-flash-preview","2026-05-14 18:16:44","2026-05-14 18:17:42",{"type":41,"vulnerable_version":42,"fixed_version":11,"vulnerable_browse":43,"vulnerable_zip":44,"fixed_browse":45,"fixed_zip":46,"all_tags":47},"plugin","5.9.8.4","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fprofilegrid-user-profiles-groups-and-communities\u002Ftags\u002F5.9.8.4","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fprofilegrid-user-profiles-groups-and-communities.5.9.8.4.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fprofilegrid-user-profiles-groups-and-communities\u002Ftags\u002F5.9.8.5","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fprofilegrid-user-profiles-groups-and-communities.5.9.8.5.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fprofilegrid-user-profiles-groups-and-communities\u002Ftags"]