[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$ffFp0EjLiukj5eZ6vh3ca_ovEbK8A4obXV9boGLtC91Q":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":20,"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":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":40},"CVE-2026-61952","bulk-edit-products-for-woocommerce-wp-sheet-editor-missing-authorization","Bulk Edit Products for WooCommerce – WP Sheet Editor \u003C= 1.8.21 - Missing Authorization","The Bulk Edit Products for WooCommerce – WP Sheet Editor plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.8.21. This makes it possible for authenticated attackers, with author-level access and above, to perform an unauthorized action.","woo-bulk-edit-products",null,"\u003C=1.8.21","1.8.22","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Missing Authorization","2026-07-12 00:00:00","2026-07-14 19:16:29",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F3a7f6fa5-ea69-4c58-994c-f9d3f3357a33?source=api-prod",3,[22,23,24,25,26,27,28,29],"modules\u002Fcolumns-visibility\u002Fcolumns-visibility.php","modules\u002Ffilters\u002Ffilters.php","modules\u002Fwp-sheet-editor\u002Fassets\u002Fcss\u002Fstyles.css","modules\u002Fwp-sheet-editor\u002Fassets\u002Fcss\u002Fstyles.min.css","modules\u002Fwp-sheet-editor\u002Fassets\u002Fjs\u002Fscripts.js","modules\u002Fwp-sheet-editor\u002Fassets\u002Fjs\u002Fscripts.min.js","modules\u002Fwp-sheet-editor\u002Fassets\u002Fvendor\u002Fcss\u002Flibraries.css","modules\u002Fwp-sheet-editor\u002Fassets\u002Fvendor\u002Fcss\u002Flibraries.min.css","researched",false,"# Exploitation Research Plan: CVE-2026-61952 - WP Sheet Editor Missing Authorization\n\n## 1. Vulnerability Summary\nThe **Bulk Edit Products for WooCommerce – WP Sheet Editor** plugin (versions \u003C= 1.8.21) contains a missing authorization vulnerability in its AJAX handlers. Specifically, functions related to column visibility management (e.g., `remove_column`, `update_columns_settings`) lack sufficient capability checks. While `restore_columns` includes a check for `manage_options`, other adjacent functions in `WP_Sheet_Editor_Columns_Visibility` only verify the nonce but fail to restrict the action to administrators. This allows authenticated users with Author-level access to modify global plugin settings, such as hiding columns for all users or altering spreadsheet visibility configurations.\n\n## 2. Attack Vector Analysis\n- **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Vulnerable Action**: `vgse_remove_column` (and potentially `vgse_update_columns_visibility`)\n- **Required Authentication**: Authenticated, Author-level access (`PR:L`). Authors generally have access to the WooCommerce Product spreadsheet if they have the `edit_products` capability.\n- **Payload Parameters**:\n  - `action`: `vgse_remove_column`\n  - `post_type`: The post type slug (e.g., `product`)\n  - `column`: The internal key of the column to remove (e.g., `_regular_price`, `_sku`)\n  - `nonce`: A valid security nonce extracted from the editor page.\n\n## 3. Code Flow\n1.  **Registration**: In `modules\u002Fcolumns-visibility\u002Fcolumns-visibility.php`, the `init()` method registers several AJAX actions:\n    ```php\n    add_action( 'wp_ajax_vgse_remove_column', array( $this, 'remove_column' ) );\n    add_action( 'wp_ajax_vgse_update_columns_visibility', array( $this, 'update_columns_settings' ) );\n    ```\n2.  **Missing Check**: In version 1.8.21, the `remove_column()` function (and `update_columns_settings`) likely performs a nonce check using `VGSE()->helpers->verify_nonce_from_request()` but lacks the secondary capability check seen in `restore_columns()`:\n    ```php\n    \u002F\u002F Contrast with restore_columns() which HAS the check:\n    if ( ! VGSE()->helpers->verify_nonce_from_request() || ! VGSE()->helpers->user_can_manage_options() ) {\n        wp_send_json_error(...);\n    }\n    ```\n3.  **Sink**: The function calls `save_removed_columns($columns, $post_type)`, which executes `update_option( $this->removed_columns_key, $removed_columns, false )`. This updates the site-wide `vgse_removed_columns` option, affecting all users' view of the spreadsheet.\n\n## 4. Nonce Acquisition Strategy\nThe nonce is localized for the spreadsheet editor. Since the vulnerability requires Author-level access, we must obtain the nonce from the editor interface.\n\n1.  **Identify Editor Page**: The Product Editor page is typically located at `\u002Fwp-admin\u002Fadmin.php?page=vgse-view-product`.\n2.  **Access Page**: Use the `browser_navigate` tool to go to this URL as an Author.\n3.  **Extract Nonce**: The plugin localizes settings in the `vgse_editor_settings` object.\n    - **JS Variable**: `window.vgse_editor_settings`\n    - **Nonce Key**: `nonce`\n4.  **Execution**: Use `browser_eval(\"window.vgse_editor_settings?.nonce\")` to retrieve the token.\n\n## 5. Exploitation Strategy\n### Step-by-Step Plan\n1.  **Preparation**: Ensure the environment has WooCommerce and the WP Sheet Editor plugin active. Create an Author user.\n2.  **Nonce Retrieval**:\n    - Log in as the Author.\n    - Navigate to the Product Sheet: `\u002Fwp-admin\u002Fadmin.php?page=vgse-view-product`.\n    - Extract the nonce using `browser_eval`.\n3.  **Malicious Request**:\n    - Use the `http_request` tool to send a POST request to `admin-ajax.php`.\n    - **Target**: Remove the \"Regular Price\" column (`_regular_price`) to disrupt store management.\n4.  **HTTP Request Details**:\n    - **URL**: `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n    - **Method**: `POST`\n    - **Headers**: `Content-Type: application\u002Fx-www-form-urlencoded`\n    - **Body**:\n      ```text\n      action=vgse_remove_column&post_type=product&column=_regular_price&nonce=[EXTRACTED_NONCE]\n      ```\n\n## 6. Test Data Setup\n1.  **Install**: WooCommerce and \"Bulk Edit Products for WooCommerce – WP Sheet Editor\".\n2.  **Content**: Add at least one test product so the spreadsheet loads data.\n3.  **User**: Create a user with the `author` role. Ensure they have the `edit_products` capability (default for WooCommerce Authors).\n\n## 7. Expected Results\n- **Response**: The AJAX request should return a JSON success message (e.g., `{\"success\":true,\"data\":{...}}`).\n- **Impact**: The \"Regular Price\" column will disappear from the spreadsheet for *all* users, including administrators.\n- **Database**: The WordPress option `vgse_removed_columns` will now contain `_regular_price` for the `product` entry.\n\n## 8. Verification Steps\nAfter the exploit, use WP-CLI to verify the state of the system:\n1.  **Check Options**:\n    ```bash\n    wp option get vgse_removed_columns --format=json\n    ```\n2.  **Verify Content**: Ensure the output JSON includes `\"_regular_price\"` under the `product` key.\n3.  **UI Verification**: Navigate to the editor as an Administrator and confirm the \"Regular Price\" column is missing from the table.\n\n## 9. Alternative Approaches\nIf `vgse_remove_column` is patched or behaves differently, attempt to exploit `vgse_update_columns_visibility`:\n- **Action**: `vgse_update_columns_visibility`\n- **Body**: `action=vgse_update_columns_visibility&post_type=product&columns[0][key]=_regular_price&columns[0][status]=disabled&nonce=[NONCE]`\n- This endpoint targets the visibility status settings stored in `vgse_columns_visibility`.","The Bulk Edit Products for WooCommerce – WP Sheet Editor plugin (\u003C= 1.8.21) contains a missing authorization vulnerability in its column visibility AJAX handlers. Authenticated attackers with Author-level access can bypass capability checks to globally hide or modify spreadsheet columns by sending unauthorized AJAX requests. This allows lower-privileged users to manipulate site-wide spreadsheet configurations and disrupt store management.","\u002F\u002F modules\u002Fcolumns-visibility\u002Fcolumns-visibility.php lines 34-36\nadd_action( 'wp_ajax_vgse_update_columns_visibility', array( $this, 'update_columns_settings' ) );\nadd_action( 'wp_ajax_vgse_remove_column', array( $this, 'remove_column' ) );\nadd_action( 'wp_ajax_vgse_restore_columns', array( $this, 'restore_columns' ) );\n\n---\n\n\u002F\u002F modules\u002Fcolumns-visibility\u002Fcolumns-visibility.php lines 218+\npublic function update_columns_settings() {\n    if ( ! empty( $_POST['extra_data'] ) ) {\n        \u002F\u002F When we render the form in the spreadsheet editor, we send the form data as JSON in extra_data because some servers have low limits for form post fields\n        $extra_data = json_decode( html_entity_decode( wp_unslash( $_POST['extra_data'] ) ), true );\n        if ( ! is_array( $extra_data ) ) {\n            wp_send_json_error( array( 'message' => esc_html__( 'We received invalid column data. Please make sure that your column titles don\\'t contain special characters.', 'vg_sheet_editor' ) ) );\n        }\n        \u002F\u002F ... (missing capability check before processing data and updating options)","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwoo-bulk-edit-products\u002F1.8.21\u002Fmodules\u002Fcolumns-visibility\u002Fcolumns-visibility.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwoo-bulk-edit-products\u002F1.8.22\u002Fmodules\u002Fcolumns-visibility\u002Fcolumns-visibility.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwoo-bulk-edit-products\u002F1.8.21\u002Fmodules\u002Fcolumns-visibility\u002Fcolumns-visibility.php\t2026-01-05 23:38:38.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwoo-bulk-edit-products\u002F1.8.22\u002Fmodules\u002Fcolumns-visibility\u002Fcolumns-visibility.php\t2026-07-09 00:05:20.000000000 +0000\n@@ -218,7 +218,8 @@\n \t\tpublic function update_columns_settings() {\n \t\t\tif ( ! empty( $_POST['extra_data'] ) ) {\n \t\t\t\t\u002F\u002F When we render the form in the spreadsheet editor, we send the form data as JSON in extra_data because some servers have low limits for form post fields\n-\t\t\t\t$extra_data = json_decode( html_entity_decode( wp_unslash( $_POST['extra_data'] ) ), true );\n+\t\t\t\t$extra_data = json_decode( wp_unslash( $_POST['extra_data'] ), true );\n+\t\t\t\t\n \t\t\t\tif ( ! is_array( $extra_data ) ) {\n \t\t\t\t\twp_send_json_error( array( 'message' => esc_html__( 'We received invalid column data. Please make sure that your column titles don\\'t contain special characters.', 'vg_sheet_editor' ) ) );\n \t\t\t\t}\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwoo-bulk-edit-products\u002F1.8.21\u002Fmodules\u002Ffilters\u002Ffilters.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwoo-bulk-edit-products\u002F1.8.22\u002Fmodules\u002Ffilters\u002Ffilters.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwoo-bulk-edit-products\u002F1.8.21\u002Fmodules\u002Ffilters\u002Ffilters.php\t2026-01-17 02:49:02.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwoo-bulk-edit-products\u002F1.8.22\u002Fmodules\u002Ffilters\u002Ffilters.php\t2026-07-09 00:05:20.000000000 +0000\n@@ -196,12 +196,12 @@\n \t\t\t\t$internal_join = 'OR';\n \t\t\t}\n \n-\t\t\t$checks          = array();\n \t\t\t$search_columns  = array( 'post_title', 'post_content', 'post_excerpt' );\n \t\t\t$phrases         = array_map( 'trim', explode( ';', $raw_keywords ) );\n \t\t\t$prepared_values = array();\n \t\t\t$phrase_checks   = array();\n \t\t\tforeach ( $phrases as $phrase ) {\n+\t\t\t\t$word_checks_for_phrase = array();\n \t\t\t\t$words = explode( ' ', $phrase );\n \t\t\t\tif ( empty( $words ) ) {\n \t\t\t\t\tcontinue;\n@@ -210,7 +210,7 @@\n \t\t\t\tforeach ( $words as $word ) {\n \t\t\t\t\t$word_checks = array();\n \t\t\t\t\tforeach ( $search_columns as $search_column ) {\n-\t\t\t\t\t\t$word_checks[]   = $wpdb->posts . '.%i ' . $operator . ' %s';\n+\t\t\t\t\t\t$word_checks[] = $wpdb->posts . '.%i ' . $operator . ' %s';\n \t\t\t\t\t\t$prepared_values = array_merge( $prepared_values, array( $search_column, '%' . $wpdb->esc_like( $word ) . '%' ) );\n \t\t\t\t\t}\n \t\t\t\t\tif ( is_numeric( $phrase ) ) {\n@@ -218,14 +218,16 @@\n \t\t\t\t\t\t$prepared_values[] = 'ID';\n \t\t\t\t\t\t$prepared_values[] = intval( $phrase );\n \t\t\t\t\t}\n-\t\t\t\t\t$phrase_checks[] = '( ' . implode( \" $internal_join \", $word_checks ) . ' )';\n+\t\t\t\t\t$word_checks_for_phrase[] = '( ' . implode( \" $internal_join \", $word_checks ) . ' )';\n \t\t\t\t}\n-\t\t\t\t$all_checks = implode( ' AND ', $phrase_checks );\n-\t\t\t\t$checks     = apply_filters( 'vg_sheet_editor\u002Ffilters\u002Fsearch_by_keyword_clauses\u002Fkeyword_check', $all_checks, $phrase, $clauses, $raw_keywords, $operator, $internal_join );\n+\t\t\t\t$all_checks = implode( ' AND ', $word_checks_for_phrase );\n+\n+\t\t\t\t$phrase_checks[] = apply_filters( 'vg_sheet_editor\u002Ffilters\u002Fsearch_by_keyword_clauses\u002Fkeyword_check', $all_checks, $phrase, $clauses, $raw_keywords, $operator, $internal_join );\n \t\t\t}\n+\t\t\t$checks = '( ' . implode( $operator === 'NOT LIKE' ? ' AND ' : ' OR ', $phrase_checks ) . ' )';\n \t\t\t\u002F\u002F phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared\n \t\t\t$checks            = $wpdb->prepare( $checks, $prepared_values );\n-\t\t\t$clauses['where'] .= ' AND ( ( ' . $checks . ' ) ) ';\n+\t\t\t$clauses['where'] .= ' AND ( ' . $checks . ' ) ';\n \t\t\treturn apply_filters( 'vg_sheet_editor\u002Ffilteres\u002Fsearch_by_keyword_clauses', $clauses, $raw_keywords, $operator, $internal_join );\n \t\t}","The exploit requires an authenticated user with at least Author-level privileges. First, the attacker accesses the product spreadsheet editor page (vgse-view-product) to extract the localized security nonce from the 'vgse_editor_settings' JavaScript object. Using this nonce, the attacker sends a POST request to 'admin-ajax.php' with the 'action' parameter set to 'vgse_remove_column' or 'vgse_update_columns_visibility'. By providing the desired column key (e.g., '_regular_price'), the attacker triggers the 'save_removed_columns' method, which updates the 'vgse_removed_columns' WordPress option globally, effectively hiding those columns from all users, including administrators.","gemini-3-flash-preview","2026-07-15 08:00:58","2026-07-15 08:02:08",{"type":41,"vulnerable_version":42,"fixed_version":11,"vulnerable_browse":43,"vulnerable_zip":44,"fixed_browse":45,"fixed_zip":46,"all_tags":47},"plugin","1.8.21","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwoo-bulk-edit-products\u002Ftags\u002F1.8.21","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwoo-bulk-edit-products.1.8.21.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwoo-bulk-edit-products\u002Ftags\u002F1.8.22","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwoo-bulk-edit-products.1.8.22.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwoo-bulk-edit-products\u002Ftags"]