WordPress Plugin Security Review: WC Duplicate Order
For our 31st security review of a WordPress plugin based on the voting of our customers, we reviewed the plugin WC Duplicate Order.
If you are not yet a customer of the service, once you sign up for the service as a paying customer you can start suggesting and voting on plugins to get security reviews. For those already using the service that haven’t already suggested and voted for plugins to receive a review, you can start doing that here. You can use our tool for doing limited automated security checks of plugins to see if plugins you are using have possible issues that would make them good candidates to get a review. You can also order a review of a plugin separately from our service.
The review was done on version 1.5 of WC Duplicate Order. We checked for the following issues during as part of our standard review:
- Insecure file upload handling (this is the cause of the most exploited type of vulnerability, arbitrary file upload)
- Deserialization of untrusted data
- Security issues with functions accessible through WordPress’ AJAX functionality (those have and continued to be a common source of disclosed vulnerabilities)
- Security issues with functions accessible through WordPress’ REST API (those have started to be a source of disclosed vulnerabilities)
- Persistent cross-site scripting (XSS) vulnerabilities in the frontend portions of the plugin and in the admin portions accessible to users with the Author role or below
- Cross-site request forgery (CSRF) vulnerabilities in the admin portion of the plugin
-
SQL injection vulnerabilities (the code that handles requests to the database)
-
Reflected cross-site scripting (XSS) vulnerabilities
- Security issues with functions accessible through any of the plugin’s shortcodes
- Security issues with functions accessible through the admin_action action
- Security issues with functions accessible through the admin_init action
- Security issues with import/export functionality
- Security issues with usage of is_admin()
- Security issues with usage of add_option(), delete_option(), and update_option()
- Host header injection vulnerabilities
-
Lack of protection against unintended direct access of PHP files
- Insecure and unwarranted requests to third-party websites
- Any additional possible issues identified by our Plugin Security Checker
We also checked for the following issues as part of looking into whether we should add them to our standard checks:
- Security issues with functions accessible through the admin_post action
- Usage of the extract() function
Results
We found one issue, the plugin’s duplication functionality is not properly secured and permits duplication by users that should not be able to as well as allowing duplication through cross-site request forgery (CSRF), which is where you cause someone else to take action they didn’t intend to.
We notified the developer of the plugin of the issue a week, but we haven’t heard back from them and the plugin has yet to be updated.
Privilege Escalation and Cross-Site Request Forgery (CSRF)
The plugin registers the function custom_bulk_action() to run when visiting the page /wp-admin/edit.php
23 | add_action('load-edit.php', array($this, 'custom_bulk_action')); |
Normally WordPress users with the Contributor role and above can access that.
That function doesn’t do a capabilities check to make sure the request is coming from someone that is intended to be able to duplicate orders or check for valid nonce to prevent CSRF.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | public function custom_bulk_action() { // Thanks to J Lo for the tutorial on bulk actions // https://blog.starbyte.co.uk/woocommerce-new-bulk-action/ global $typenow; $post_type = $typenow; if($post_type == 'shop_order') { $wp_list_table = _get_list_table('WP_Posts_List_Table'); $action = $wp_list_table->current_action(); $allowed_actions = array("duplicate"); if(!in_array($action, $allowed_actions)) return; if(isset($_REQUEST['post'])) { $orderids = array_map('intval', $_REQUEST['post']); } switch($action) { case "duplicate": foreach( $orderids as $orderid ) { $this->clone_order($orderid); |
When a user that isn’t intended to be able to duplicate an order makes a request to do that, the following message is shown:
You need a higher level of permission.
Sorry, you are not allowed to edit posts in this post type.
The order does get duplicated, though it may be some component isn’t duplicated.
Proof of Concept
The following proof of concept will duplicate the order specified when logged in as at least a Contributor.
Make sure to replace “[path to WordPress]” with the location of WordPress “[order ID]” with the order to duplicate.
http://[path to WordPress]/wp-admin/edit.php?s=&post_status=all&post_type=shop_order&action=duplicate&m=0&_customer_user=&paged=1&post[]=[order ID]&action2=-1