Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/dokan-lite/assets/js/frontend.asset.php
+++ b/dokan-lite/assets/js/frontend.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('dokan-hooks', 'dokan-product-editor-utils', 'dokan-react-components', 'dokan-stores-core', 'dokan-stores-product-categories', 'dokan-stores-product-editor', 'dokan-stores-products', 'dokan-utilities', 'lodash', 'react', 'react-dom', 'react-jsx-runtime', 'wc-components', 'wc-csv', 'wc-date', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-dom-ready', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-plugins', 'wp-url'), 'version' => '069544a5dddbe916033d');
+<?php return array('dependencies' => array('dokan-hooks', 'dokan-product-editor-utils', 'dokan-react-components', 'dokan-stores-core', 'dokan-stores-product-categories', 'dokan-stores-product-editor', 'dokan-stores-products', 'dokan-utilities', 'lodash', 'react', 'react-dom', 'react-jsx-runtime', 'wc-components', 'wc-csv', 'wc-date', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-dom-ready', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-plugins', 'wp-url'), 'version' => 'c4fc6678d387e35f37f4');
--- a/dokan-lite/dokan-class.php
+++ b/dokan-lite/dokan-class.php
@@ -27,7 +27,7 @@
*
* @var string
*/
- public $version = '5.0.2';
+ public $version = '5.0.3';
/**
* Instance of self
--- a/dokan-lite/dokan.php
+++ b/dokan-lite/dokan.php
@@ -3,7 +3,7 @@
* Plugin Name: Dokan
* Plugin URI: https://dokan.co/wordpress/
* Description: An e-commerce marketplace plugin for WordPress. Powered by WooCommerce and weDevs.
- * Version: 5.0.2
+ * Version: 5.0.3
* Author: Dokan Inc.
* Author URI: https://dokan.co/wordpress/
* Text Domain: dokan-lite
--- a/dokan-lite/includes/REST/CustomersController.php
+++ b/dokan-lite/includes/REST/CustomersController.php
@@ -58,27 +58,105 @@
* @return WP_Error|boolean
*/
protected function check_permission( $request, $action ) {
+ $messages = [
+ 'view' => __( 'Sorry, you cannot list resources.', 'dokan-lite' ),
+ 'create' => __( 'Sorry, you are not allowed to create resources.', 'dokan-lite' ),
+ 'edit' => __( 'Sorry, you are not allowed to edit this resource.', 'dokan-lite' ),
+ 'delete' => __( 'Sorry, you are not allowed to delete this resource.', 'dokan-lite' ),
+ 'batch' => __( 'Sorry, you are not allowed to batch update resources.', 'dokan-lite' ),
+ 'search' => __( 'Sorry, you are not allowed to search customers.', 'dokan-lite' ),
+ ];
+
if ( ! $this->check_vendor_permission() ) {
- $messages = [
- 'view' => __( 'Sorry, you cannot list resources.', 'dokan-lite' ),
- 'create' => __( 'Sorry, you are not allowed to create resources.', 'dokan-lite' ),
- 'edit' => __( 'Sorry, you are not allowed to edit this resource.', 'dokan-lite' ),
- 'delete' => __( 'Sorry, you are not allowed to delete this resource.', 'dokan-lite' ),
- 'batch' => __( 'Sorry, you are not allowed to batch update resources.', 'dokan-lite' ),
- 'search' => __( 'Sorry, you are not allowed to search customers.', 'dokan-lite' ),
- ];
return new WP_Error( "dokan_rest_cannot_$action", $messages[ $action ], [ 'status' => rest_authorization_required_code() ] );
}
+
+ // CVE-2026-8761: object-level authorization for mutating actions.
+ $target_id = isset( $request['id'] ) ? (int) $request['id'] : 0;
+ if ( $target_id > 0 && in_array( $action, [ 'view', 'edit', 'delete' ], true ) ) {
+ $allowed = $this->is_target_user_allowed( $target_id );
+ if ( is_wp_error( $allowed ) ) {
+ $status = $allowed->get_error_data();
+ $status = isset( $status['status'] ) ? (int) $status['status'] : 403;
+ return new WP_Error( "dokan_rest_cannot_$action", $messages[ $action ], [ 'status' => $status ] );
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Verify the requesting vendor may mutate the target user.
+ *
+ * Rejects targets that are missing, hold admin-grade capabilities,
+ * are themselves a vendor, or have never placed an order with the
+ * requesting vendor. CVE-2026-8761.
+ *
+ * @param int $target_id Target user id.
+ *
+ * @return true|WP_Error
+ */
+ protected function is_target_user_allowed( int $target_id ) {
+ if ( $target_id <= 0 || ! get_userdata( $target_id ) ) {
+ return new WP_Error( 'dokan_rest_invalid_target', __( 'Invalid user.', 'dokan-lite' ), [ 'status' => 404 ] );
+ }
+
+ $protected_caps = apply_filters(
+ 'dokan_rest_protected_user_caps',
+ [
+ 'manage_options',
+ 'manage_woocommerce',
+ 'edit_users',
+ 'delete_users',
+ 'list_users',
+ 'promote_users',
+ 'create_users',
+ 'remove_users',
+ ]
+ );
+ foreach ( $protected_caps as $cap ) {
+ if ( user_can( $target_id, $cap ) ) {
+ return new WP_Error( 'dokan_rest_forbidden_target', __( 'You cannot operate on this user.', 'dokan-lite' ), [ 'status' => 403 ] );
+ }
+ }
+
+ if ( dokan_is_user_seller( $target_id ) ) {
+ return new WP_Error( 'dokan_rest_forbidden_target', __( 'You cannot operate on this user.', 'dokan-lite' ), [ 'status' => 403 ] );
+ }
+
+ if ( ! dokan_customer_has_order_from_this_seller( $target_id, dokan_get_current_user_id() ) ) {
+ return new WP_Error( 'dokan_rest_forbidden_target', __( 'You cannot operate on this customer.', 'dokan-lite' ), [ 'status' => 403 ] );
+ }
+
return true;
}
/**
* Check if the current user has vendor permissions.
*
+ * Doubles as a callback on the woocommerce_rest_check_permissions
+ * filter so WooCommerce's internal capability checks for mutating
+ * operations (create/edit/delete/batch) re-validate the target user.
+ * Read context is allowed through for the vendor.
+ *
+ * @param bool|mixed $permission Original permission decision when used as a filter callback.
+ * @param string $context Operation context (read/edit/delete/create/batch).
+ * @param int $object_id Target object id.
+ * @param string $object_type Object type (expected: user).
+ *
* @return bool
*/
- public function check_vendor_permission(): bool {
- return dokan_is_user_seller( dokan_get_current_user_id() );
+ public function check_vendor_permission( $permission = false, $context = '', $object_id = 0, $object_type = '' ): bool {
+ if ( ! dokan_is_user_seller( dokan_get_current_user_id() ) ) {
+ return false;
+ }
+
+ $object_id = (int) $object_id;
+ if ( $object_id > 0 && ( '' === $object_type || 'user' === $object_type ) && in_array( $context, [ 'create', 'edit', 'delete', 'batch' ], true ) ) {
+ return ! is_wp_error( $this->is_target_user_allowed( $object_id ) );
+ }
+
+ return true;
}
/**
@@ -90,7 +168,24 @@
public function get_items( $request ) {
return $this->perform_vendor_action(
function () use ( $request ) {
- return parent::get_items( $request );
+ $response = parent::get_items( $request );
+ if ( is_wp_error( $response ) || ! ( $response instanceof WP_REST_Response ) ) {
+ return $response;
+ }
+
+ $vendor_id = dokan_get_current_user_id();
+ $data = array_values(
+ array_filter(
+ (array) $response->get_data(),
+ static function ( $item ) use ( $vendor_id ) {
+ $id = is_array( $item ) ? ( $item['id'] ?? 0 ) : 0;
+ return $id && dokan_customer_has_order_from_this_seller( $id, $vendor_id );
+ }
+ )
+ );
+
+ $response->set_data( $data );
+ return $response;
}
);
}
@@ -255,6 +350,11 @@
* @return WP_Error|WC_Data
*/
protected function prepare_object_for_database( $request, $creating = false ) {
+ // CVE-2026-8761: never allow role/roles via this endpoint.
+ if ( null !== $request->get_param( 'role' ) || null !== $request->get_param( 'roles' ) ) {
+ return new WP_Error( 'dokan_rest_forbidden_field', __( 'You cannot modify the role of a user.', 'dokan-lite' ), [ 'status' => 403 ] );
+ }
+
$customer = parent::prepare_object_for_database( $request, $creating );
if ( is_wp_error( $customer ) ) {
@@ -278,10 +378,12 @@
* @return mixed The result of the action.
*/
private function perform_vendor_action( callable $action ) {
- add_filter( 'woocommerce_rest_check_permissions', [ $this, 'check_vendor_permission' ] );
- $result = $action();
- remove_filter( 'woocommerce_rest_check_permissions', [ $this, 'check_vendor_permission' ] );
- return $result;
+ add_filter( 'woocommerce_rest_check_permissions', [ $this, 'check_vendor_permission' ], 10, 4 );
+ try {
+ return $action();
+ } finally {
+ remove_filter( 'woocommerce_rest_check_permissions', [ $this, 'check_vendor_permission' ], 10 );
+ }
}
/**
--- a/dokan-lite/includes/REST/VendorDashboardController.php
+++ b/dokan-lite/includes/REST/VendorDashboardController.php
@@ -414,6 +414,7 @@
'language' => get_locale(),
'week_start_on' => get_option( 'start_of_week' ),
'store_color' => dokan_get_option( 'store_color_pallete', 'dokan_colors', [] ),
+ 'enable_withdraw' => dokan_get_option( 'hide_withdraw_option', 'dokan_withdraw', 'off' ) === 'off',
'timezone_utc' => $timezone_utc,
'ai_settings' => [
'ai_text_enable' => $is_text_configured,
@@ -597,6 +598,12 @@
'context' => [ 'view' ],
'readonly' => true,
],
+ 'enable_withdraw' => [
+ 'description' => esc_html__( 'Enable withdraw option.', 'dokan-lite' ),
+ 'type' => 'boolean',
+ 'context' => [ 'view' ],
+ 'readonly' => true,
+ ],
'ai_settings' => [
'description' => esc_html__( 'Store AI Settings.', 'dokan-lite' ),
'type' => 'object',
--- a/dokan-lite/includes/REST/WithdrawControllerV2.php
+++ b/dokan-lite/includes/REST/WithdrawControllerV2.php
@@ -100,6 +100,7 @@
return rest_ensure_response(
[
'withdraw_method' => $default_withdraw_method,
+ 'is_manual_withdraw_enable' => ! empty( dokan_get_option( 'disbursement', 'dokan_withdraw' )['manual'] ?? false ),
'payment_methods' => array_values( $payment_methods ),
'active_methods' => $active_methods,
'setup_url' => $setup_url,
--- a/dokan-lite/templates/whats-new.php
+++ b/dokan-lite/templates/whats-new.php
@@ -4,6 +4,28 @@
*/
$changelog = [
[
+ 'version' => 'Version 5.0.3',
+ 'released' => '2026-05-21',
+ 'changes' => [
+ 'Improvement' => [
+ [
+ 'title' => 'Exposed manual withdrawal availability and withdraw-visibility flags in the vendor dashboard REST API.',
+ 'description' => '',
+ ],
+ ],
+ 'Fix' => [
+ [
+ 'title' => 'Restricted the Customers REST endpoint to self-service to prevent vendors from modifying other user accounts.',
+ 'description' => '',
+ ],
+ [
+ 'title' => 'Translated the "Actions" column header on vendor dashboard DataViews tables.',
+ 'description' => '',
+ ],
+ ],
+ ],
+ ],
+ [
'version' => 'Version 5.0.2',
'released' => '2026-05-18',
'changes' => [
--- a/dokan-lite/vendor/composer/installed.php
+++ b/dokan-lite/vendor/composer/installed.php
@@ -1,9 +1,9 @@
<?php return array(
'root' => array(
'name' => 'wedevs/dokan',
- 'pretty_version' => 'v5.0.2',
- 'version' => '5.0.2.0',
- 'reference' => '730cd74b53bb863cae25c33910721506a5c388fb',
+ 'pretty_version' => 'v5.0.3',
+ 'version' => '5.0.3.0',
+ 'reference' => 'd7fadd9a85f1b11e23841282782a45a367059c58',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -38,9 +38,9 @@
'dev_requirement' => false,
),
'wedevs/dokan' => array(
- 'pretty_version' => 'v5.0.2',
- 'version' => '5.0.2.0',
- 'reference' => '730cd74b53bb863cae25c33910721506a5c388fb',
+ 'pretty_version' => 'v5.0.3',
+ 'version' => '5.0.3.0',
+ 'reference' => 'd7fadd9a85f1b11e23841282782a45a367059c58',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),