CVE-2025-68018

Order Listener for WooCommerce <= 3.6.1 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
3.6.2
Patched in
47d
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=3.6.1
PublishedJanuary 19, 2026
Last updatedMarch 6, 2026
Affected pluginwoc-order-alert

What Changed in the Fix

Changes introduced in v3.6.2

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# 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 to permanent_dismissible to 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

  1. Entry Point: An HTTP request is sent to admin-ajax.php. This triggers the admin_init hook.
  2. Hook Registration: In includes/wp-dev-kit/classes/class-client.php, the __construct method registers the hook:
    add_action( 'admin_init', array( $this, 'manage_permanent_dismissible' ) );
    
  3. Vulnerable Function: The manage_permanent_dismissible function 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;
        }
    }
    
  4. Option Key Generation: The function calls get_notices_id($id), which returns $this->integration_server . $id. In this plugin's configuration, $this->integration_server defaults to an empty string '' (see includes/wp-dev-kit/classes/class-client.php:73). Therefore, the id parameter directly controls the option key passed to update_option.
  5. 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_dismissible
    • id=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

Research Findings
Static analysis — not yet PoC-verified

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

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/woc-order-alert/3.6.1/includes/class-hooks.php /home/deploy/wp-safety.org/data/plugin-versions/woc-order-alert/3.6.2/includes/class-hooks.php
--- /home/deploy/wp-safety.org/data/plugin-versions/woc-order-alert/3.6.1/includes/class-hooks.php	2025-07-15 07:15:18.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/woc-order-alert/3.6.2/includes/class-hooks.php	2026-02-21 06:43:54.000000000 +0000
@@ -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.