From 31d25e06dcd165973b54291f8f3f12a4169532ba Mon Sep 17 00:00:00 2001 From: jekkos Date: Fri, 6 Mar 2026 13:18:47 +0100 Subject: [PATCH] fix(security): whitelist and validate invoice template types (#4393) - Add whitelist validation for invoice_type to prevent path traversal and LFI - Validate invoice_type against allowed values in Sale_lib - Sanitize invoice_type input in Config controller before saving - Default to 'invoice' template for invalid types Security: Prevents arbitrary file inclusion via user-controlled invoice_type config --- app/Controllers/Config.php | 4 +++- app/Controllers/Sales.php | 10 ++++++++-- app/Libraries/Sale_lib.php | 15 ++++++++++++--- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/app/Controllers/Config.php b/app/Controllers/Config.php index 9121f12ea..820ee11c8 100644 --- a/app/Controllers/Config.php +++ b/app/Controllers/Config.php @@ -942,7 +942,9 @@ class Config extends Secure_Controller 'work_order_enable' => $this->request->getPost('work_order_enable') != null, 'work_order_format' => $this->request->getPost('work_order_format'), 'last_used_work_order_number' => $this->request->getPost('last_used_work_order_number', FILTER_SANITIZE_NUMBER_INT), - 'invoice_type' => $this->request->getPost('invoice_type') + 'invoice_type' => Sale_lib::isValidInvoiceType($this->request->getPost('invoice_type')) + ? $this->request->getPost('invoice_type') + : 'invoice' ]; $success = $this->appconfig->batch_save($batch_save_data); diff --git a/app/Controllers/Sales.php b/app/Controllers/Sales.php index d79d645df..81033a3ab 100644 --- a/app/Controllers/Sales.php +++ b/app/Controllers/Sales.php @@ -755,8 +755,11 @@ class Sales extends Secure_Controller $data['sale_status'] = COMPLETED; $sale_type = SALE_TYPE_INVOICE; - // The PHP file name is the same as the invoice_type key - $invoice_view = $this->config['invoice_type']; + $invoice_type = $this->config['invoice_type']; + if (!Sale_lib::isValidInvoiceType($invoice_type)) { + $invoice_type = 'invoice'; + } + $invoice_view = $invoice_type; // Save the data to the sales table $data['sale_id_num'] = $this->sale->save_value($sale_id, $data['sale_status'], $data['cart'], $customer_id, $employee_id, $data['comments'], $invoice_number, $work_order_number, $quote_number, $sale_type, $data['payments'], $data['dinner_table'], $tax_details); @@ -1107,6 +1110,9 @@ class Sales extends Secure_Controller } $invoice_type = $this->config['invoice_type']; + if (!Sale_lib::isValidInvoiceType($invoice_type)) { + $invoice_type = 'invoice'; + } $data['invoice_view'] = $invoice_type; return $data; diff --git a/app/Libraries/Sale_lib.php b/app/Libraries/Sale_lib.php index 72e12e8fe..d2a4ac273 100644 --- a/app/Libraries/Sale_lib.php +++ b/app/Libraries/Sale_lib.php @@ -88,9 +88,13 @@ class Sale_lib return $register_modes; } - /** - * @return array - */ + private const ALLOWED_INVOICE_TYPES = [ + 'invoice', + 'tax_invoice', + 'custom_invoice', + 'custom_tax_invoice' + ]; + public function get_invoice_type_options(): array { $invoice_types = []; @@ -101,6 +105,11 @@ class Sale_lib return $invoice_types; } + public static function isValidInvoiceType(string $invoice_type): bool + { + return in_array($invoice_type, self::ALLOWED_INVOICE_TYPES, true); + } + /** * @return array */