Order Listener for WooCommerce <= 3.6.1 - Missing Authorization
Description
The Order Listener for WooCommerce plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 3.6.1. 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
<=3.6.1What Changed in the Fix
Changes introduced in v3.6.2
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2025-68018 ## 1. Vulnerability Summary The **Order Notification for WooCommerce** plugin (versions <= 3.6.1) is vulnerable to **Missing Authorization** due to the use of an insecure version of the **WP-Dev-Kit (WPDK)** SDK. Specifically, the `WPDK\Client` class …
Show full research plan
Exploitation Research Plan - CVE-2025-68018
1. Vulnerability Summary
The Order Notification for WooCommerce plugin (versions <= 3.6.1) is vulnerable to Missing Authorization due to the use of an insecure version of the WP-Dev-Kit (WPDK) SDK.
Specifically, the WPDK\Client class (included in the plugin) registers a function manage_permanent_dismissible to the admin_init hook. In WordPress, admin_init is triggered for any request to /wp-admin/admin-ajax.php, regardless of whether the user is authenticated. The manage_permanent_dismissible function fails to perform any capability checks or nonce validations before calling update_option(). This allows an unauthenticated attacker to overwrite arbitrary WordPress options with a numeric timestamp, leading to unauthorized configuration changes (e.g., enabling user registration).
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - HTTP Method:
GET - Parameters:
pb_action: Must be set topermanent_dismissibleto trigger the vulnerable code path.id: The name of the WordPress option to overwrite (e.g.,users_can_register).
- Authentication: None required (unauthenticated).
- Preconditions: The plugin must be active.
3. Code Flow
- Entry Point: An HTTP request is sent to
admin-ajax.php. This triggers theadmin_inithook. - Hook Registration: In
includes/wp-dev-kit/classes/class-client.php, the__constructmethod registers the hook:add_action( 'admin_init', array( $this, 'manage_permanent_dismissible' ) ); - Vulnerable Function: The
manage_permanent_dismissiblefunction executes:function manage_permanent_dismissible() { $query_args = wp_unslash( array_map( 'sanitize_text_field', $_GET ) ); if ( Utils::get_args_option( 'pb_action', $query_args ) == 'permanent_dismissible' && ! empty( $id = Utils::get_args_option( 'id', $query_args ) ) ) { // Overwrites the option named in 'id' with the current timestamp update_option( $this->get_notices_id( $id ), time() ); // Redirects to wp-admin wp_safe_redirect( site_url( 'wp-admin' ) ); exit; } } - Option Key Generation: The function calls
get_notices_id($id), which returns$this->integration_server . $id. In this plugin's configuration,$this->integration_serverdefaults to an empty string''(seeincludes/wp-dev-kit/classes/class-client.php:73). Therefore, theidparameter directly controls the option key passed toupdate_option. - Sink:
update_option($id, time())is executed without authorization checks.
4. Nonce Acquisition Strategy
This vulnerability does not require a nonce. The manage_permanent_dismissible function in class-client.php lacks any calls to check_admin_referer, check_ajax_referer, or wp_verify_nonce.
5. Exploitation Strategy
We will exploit this to enable public user registration on the site by overwriting the users_can_register option.
Step 1: Trigger Option Overwrite
Send a GET request to the vulnerable endpoint targeting the users_can_register option.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Query Parameters:
pb_action=permanent_dismissibleid=users_can_register
Step 2: Verification
Check if the option value has changed from 0 (disabled) to a large integer (the timestamp), which WordPress evaluates as true.
6. Test Data Setup
1
Summary
The Order Notification for WooCommerce plugin (versions <= 3.6.1) includes an insecure version of the WPDK SDK that allows unauthenticated attackers to overwrite arbitrary WordPress options. By targeting the 'admin_init' hook via a request to admin-ajax.php, an attacker can set sensitive options like 'users_can_register' to a numeric timestamp, potentially enabling open registration and leading to site takeover.
Vulnerable Code
// includes/wp-dev-kit/classes/class-client.php:91 add_action( 'admin_init', array( $this, 'manage_permanent_dismissible' ) ); --- // includes/wp-dev-kit/classes/class-client.php:136 /** * Manage permanent dismissible of any notice */ function manage_permanent_dismissible() { $query_args = wp_unslash( array_map( 'sanitize_text_field', $_GET ) ); if ( Utils::get_args_option( 'pb_action', $query_args ) == 'permanent_dismissible' && ! empty( $id = Utils::get_args_option( 'id', $query_args ) ) ) { // update value update_option( $this->get_notices_id( $id ), time() ); // Redirect wp_safe_redirect( site_url( 'wp-admin' ) ); exit; } }
Security Fix
@@ -26,7 +26,7 @@ add_action( 'admin_bar_menu', array( $this, 'handle_admin_bar_menu' ), 9999, 1 ); add_filter( 'woocommerce_webhook_deliver_async', '__return_false' ); - add_filter( 'woocommerce_rest_check_permissions', '__return_true' ); + add_filter( 'woocommerce_rest_check_permissions', array( $this, 'woa_check_permissions' ), 10, 4 ); add_filter( 'plugin_row_meta', array( $this, 'add_plugin_meta' ), 10, 2 ); add_filter( 'plugin_action_links_' . OLISTENER_PLUGIN_FILE, array( $this, 'add_plugin_actions' ), 10, 2 ); @@ -35,6 +35,22 @@ add_action( 'woocommerce_new_order', array( $this, 'woocommerce_new_order' ), 10, 2 ); } + /** + * Proper permission check for WooCommerce REST API + * + * @param bool $permission Current permission value + * @param string $context Request context (read/write) + * @param int $object_id Post / product ID + * @param string $post_type Post type (product, order, etc.) + * @return bool Permission result + */ + public function woa_check_permissions( $permission, $context, $object_id, $post_type ) { + if ( current_user_can( 'manage_woocommerce' ) ) { + return true; + } + return $permission; + } + /** * Add capabilities to shop manager for Order Notifier
Exploit Outline
The exploit targets the manage_permanent_dismissible function in the WPDK SDK component. 1. Target Endpoint: Any request to /wp-admin/admin-ajax.php, which triggers the 'admin_init' hook. 2. Payload: A GET request with query parameters 'pb_action=permanent_dismissible' and 'id=[TARGET_OPTION]'. 3. Authentication: No authentication or nonces are required as 'admin_init' runs for unauthenticated AJAX requests and the function lacks capability checks. 4. Impact: The vulnerable code calls update_option() on the provided ID. By setting 'id=users_can_register', the attacker overwrites the WordPress registration option with a current timestamp. WordPress treats any non-zero value for this option as 'true', enabling public user registration.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.