WCFM - WooCommerce Frontend Manager <= 6.7.25 - Insecure Direct Object References to Autenticated (Vendor+) Arbitrary Post/Product Manipulation
Description
The WCFM – Frontend Manager for WooCommerce along with Bookings Subscription Listings Compatible plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 6.7.25 via multiple AJAX actions including `wcfm_modify_order_status`, `delete_wcfm_article`, `delete_wcfm_product`, and the article management controller due to missing validation on user-supplied object IDs. This makes it possible for authenticated attackers, with Vendor-level access and above, to modify the status of any order, delete or modify any post/product/page, regardless of ownership.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:HTechnical Details
<=6.7.25What Changed in the Fix
Changes introduced in v6.7.26
Source Code
WordPress.org SVNThis research plan outlines the steps to verify the Insecure Direct Object Reference (IDOR) vulnerability in the WCFM - WooCommerce Frontend Manager plugin, allowing vendors to manipulate products, orders, and articles they do not own. ### 1. Vulnerability Summary The WCFM plugin (<= 6.7.25) fails …
Show full research plan
This research plan outlines the steps to verify the Insecure Direct Object Reference (IDOR) vulnerability in the WCFM - WooCommerce Frontend Manager plugin, allowing vendors to manipulate products, orders, and articles they do not own.
1. Vulnerability Summary
The WCFM plugin (<= 6.7.25) fails to validate object ownership in several AJAX handlers. While these handlers verify that the user has a "Vendor" or "Shop Staff" role, they do not check if the specific ID provided in the request (Product ID, Order ID, or Article ID) belongs to the authenticated user. This allows any authenticated vendor to modify or delete content belonging to other vendors or the site administrator.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Authentication: Required (User role:
wcfm_vendor,seller, orvendor) - Vulnerable Actions:
delete_wcfm_productwcfm_modify_order_statusdelete_wcfm_articlewcfm_ajax_controller(withcontroller=wcfm-products-manage)
- Payload Parameters:
productid(for product deletion)order_id&order_status(for order manipulation)articleid(for article deletion)wcfm_ajax_nonce(required CSRF token)
3. Code Flow
- AJAX Registration: In
core/class-wcfm-ajax.php, hooks are registered forwp_ajax_delete_wcfm_productandwp_ajax_wcfm_modify_order_status. - Central Controller: For management actions,
wcfm_ajax_controller()is used. It checks for general capabilities:// core/class-wcfm-ajax.php if ( !current_user_can( 'manage_woocommerce' ) && !current_user_can( 'wcfm_vendor' ) && ... ) { wp_send_json_error( ... ); } - Missing Ownership Check: The handlers (e.g.,
delete_wcfm_product) take aproductidfrom$_POST. They typically callwp_delete_post()or similar functions without first checking if thepost_authormatches theget_current_user_id().
4. Nonce Acquisition Strategy
WCFM localizes its AJAX nonce into a global JavaScript object named wcfm_params.
- Identify Trigger: The nonce is enqueued on WCFM dashboard pages (e.g.,
/wcfm-dashboard/,/wcfm-products/). - Access Page: Navigate to the WCFM Products page as the Vendor user.
- Extract Nonce: Use
browser_evalto retrieve the nonce from thewcfm_paramsobject.- JS Variable:
window.wcfm_params?.wcfm_ajax_nonce
- JS Variable:
5. Exploitation Strategy
We will demonstrate the IDOR by deleting an Administrator's product using a Vendor account.
Step 1: Product Deletion (Primary PoC)
- Method: POST
- URL:
https://<target>/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=delete_wcfm_product &productid=<ADMIN_PRODUCT_ID> &wcfm_ajax_nonce=<EXTRACTED_NONCE>
Step 2: Order Status Modification
- Method: POST
- URL:
https://<target>/wp-admin/admin-ajax.php - Body:
action=wcfm_modify_order_status &order_id=<TARGET_ORDER_ID> &order_status=completed &wcfm_ajax_nonce=<EXTRACTED_NONCE>
6. Test Data Setup
- Administrator Actions:
- Create a product (Type:
product, Title: "Admin Sensitive Product"). Note the ID. - Create a WooCommerce Order. Note the ID.
- Create a Post (Type:
post, Title: "Admin Article"). Note the ID.
- Create a product (Type:
- Vendor Setup:
- Create a user with the
wcfm_vendorrole.
- Create a user with the
- WCFM Configuration:
- Ensure WCFM is active and the Vendor has access to the dashboard.
7. Expected Results
- Deletion: The server should return a success JSON response (e.g.,
{"status": true}). The product with the specified ID should be moved to the trash or permanently deleted. - Order Update: The order status should change to
completedin the WooCommerce database, regardless of whether the vendor is associated with the products in that order.
8. Verification Steps
- Check Product Status: Use WP-CLI to verify the product is gone.
wp post get <ADMIN_PRODUCT_ID> --field=post_status(Should be 'trash' or return error if deleted).
- Check Order Status:
wp wc order get <TARGET_ORDER_ID> --field=status(Should be 'completed').
- Check Article Status:
wp post get <ADMIN_ARTICLE_ID> --field=post_status
9. Alternative Approaches
If delete_wcfm_product is patched or behaves differently, use the wcfm_ajax_controller to attempt an edit on an unauthorized product:
- Action:
wcfm_ajax_controller - Controller:
wcfm-products-manage - Body:
controller=wcfm-products-manage&wcfm_products_manage_form=...&proid=<ADMIN_PRODUCT_ID>&wcfm_ajax_nonce=<NONCE> - This tests the IDOR within the complex product manager logic rather than the simple delete hook.
Summary
The WCFM – Frontend Manager for WooCommerce plugin is vulnerable to Insecure Direct Object Reference (IDOR) due to missing ownership validation in several AJAX handlers. This allow authenticated vendors to delete or modify products, orders, and articles belonging to other vendors or administrators by specifying the target object's ID in the request.
Vulnerable Code
// core/class-wcfm-ajax.php:206 if ( !current_user_can( 'manage_woocommerce' ) && !current_user_can( 'wcfm_vendor' ) && !current_user_can( 'seller' ) && !current_user_can( 'vendor' ) && !current_user_can( 'shop_staff' ) ) { wp_send_json_error( esc_html__( 'You don’t have permission to do this.', 'woocommerce' ) ); wp_die(); } // core/class-wcfm-ajax.php:220 case 'wcfm-products-manage': if ( !current_user_can( 'manage_woocommerce' ) && !current_user_can( 'wcfm_vendor' ) && !current_user_can( 'seller' ) && !current_user_can( 'vendor' ) && !current_user_can( 'shop_staff' ) ) { wp_send_json_error( esc_html__( 'You don’t have permission to do this.', 'woocommerce' ) ); wp_die(); } if( wcfm_is_booking() ) { include_once( $this->controllers_path . 'wc_bookings/wcfm-controller-wcbookings-products-manage.php' ); new WCFM_WCBookings_Products_Manage_Controller(); } // Integration controllers are initialized using $_POST parameters without ownership checks include_once( $this->controllers_path . 'products-manager/wcfm-controller-integrations-products-manage.php' ); new WCFM_Integrations_Products_Manage_Controller(); --- // core/class-wcfm-ajax.php:49 add_action( 'wp_ajax_wcfm_modify_order_status', array( &$this, 'wcfm_modify_order_status' ) ); // core/class-wcfm-ajax.php:52 add_action( 'wp_ajax_delete_wcfm_product', array( &$this, 'delete_wcfm_product' ) ); --- // core/class-wcfm-article.php:46 add_action( 'wp_ajax_delete_wcfm_article', array( &$this, 'delete_wcfm_article' ) );
Security Fix
@@ -1,4 +1,5 @@ <?php + /** * WCFM plugin controllers * @@ -10,390 +11,391 @@ */ class WCFM_Orders_WCFMMarketplace_Controller { -
Exploit Outline
The attacker requires a valid account with at least Vendor-level permissions (e.g., 'wcfm_vendor'). 1. Login to the WordPress site as a Vendor. 2. Access any WCFM dashboard page (e.g., /wcfm-dashboard/) to obtain the 'wcfm_ajax_nonce' from the 'wcfm_params' global JavaScript variable. 3. Identify the ID of a target product, order, or article that the vendor does not own (e.g., an administrator's product). 4. Send a POST request to /wp-admin/admin-ajax.php with the 'action' parameter set to a vulnerable handler (e.g., 'delete_wcfm_product', 'wcfm_modify_order_status', or 'delete_wcfm_article'). 5. Include the target ID in the corresponding ID parameter (e.g., 'productid', 'order_id', or 'articleid') and provide the 'wcfm_ajax_nonce'. 6. The server will execute the action (deletion or modification) because it verifies the user's role and nonce but fails to verify that the target object ID belongs to the requesting user.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.