From e87e4eb18749e494075063055166321c7ce2153d Mon Sep 17 00:00:00 2001 From: Zakaria Boushaba <48571684+Boushabazakaria@users.noreply.github.com> Date: Mon, 13 Apr 2026 12:25:05 +0100 Subject: [PATCH 01/75] Fix: fallback to numeric VAT rate match when default_vat_code is null (#37830) * Fix: fallback to numeric VAT rate match when default_vat_code is not set on product * fix: restore VAT rate assignment for input box case alongside combo fallback --------- Co-authored-by: Zakaria Boushaba --- htdocs/core/tpl/objectline_create.tpl.php | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/htdocs/core/tpl/objectline_create.tpl.php b/htdocs/core/tpl/objectline_create.tpl.php index da6c68d3897..3226c49f6f5 100644 --- a/htdocs/core/tpl/objectline_create.tpl.php +++ b/htdocs/core/tpl/objectline_create.tpl.php @@ -943,13 +943,20 @@ if (!empty($usemargins) && $user->hasRight('margins', 'creer')) { } - // Set vat rate if field is an input box - $('#tva_tx').val(tva_tx); - // Set vat rate by selecting the combo - //$('#tva_tx option').val(tva_tx); // This is bugged, it replaces the vat key of all options - $('#tva_tx option').removeAttr('selected'); - console.log("stringforvatrateselection="+stringforvatrateselection+" -> value of option label for this key="+$('#tva_tx option[value="'+stringforvatrateselection+'"]').val()); - $('#tva_tx option[value="'+stringforvatrateselection+'"]').prop('selected', true); + // Set vat rate: handle both input box and combo cases + if ($('#tva_tx option').length) { + // It is a combo: try exact match first (rate + code), fallback to numeric match + if ($('#tva_tx option[value="' + stringforvatrateselection + '"]').length) { + $('#tva_tx').val(stringforvatrateselection); + } else { + $('#tva_tx option').filter(function () { + return parseFloat($(this).val()) === parseFloat(tva_tx); + }).first().prop('selected', true); + } + } else { + // It is an input box + $('#tva_tx').val(tva_tx); + } Date: Tue, 14 Apr 2026 19:31:07 +0200 Subject: [PATCH 02/75] FIX SQL Injection via Operator Injection in Contract Service List This vulnerability was discovered and reported by Nguy Minh Tuan (@minhtuanact) of Sun Cyber Security Research Team. --- htdocs/contrat/services_list.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/htdocs/contrat/services_list.php b/htdocs/contrat/services_list.php index c120a3add47..6860bf941ba 100644 --- a/htdocs/contrat/services_list.php +++ b/htdocs/contrat/services_list.php @@ -323,28 +323,28 @@ if ($filter_datecloture_start != '' && $filter_opcloture == -1) { } if (!empty($filter_opouvertureprevue) && $filter_opouvertureprevue != -1 && $filter_opouvertureprevue != ' BETWEEN ' && $filter_dateouvertureprevue_start != '') { - $sql .= " AND cd.date_ouverture_prevue ".$filter_opouvertureprevue." '".$db->idate($filter_dateouvertureprevue_start)."'"; + $sql .= " AND cd.date_ouverture_prevue ".preg_replace('/[^<>]/', '', $filter_opouvertureprevue)." '".$db->idate($filter_dateouvertureprevue_start)."'"; } if (!empty($filter_opouvertureprevue) && $filter_opouvertureprevue == ' BETWEEN ') { - $sql .= " AND cd.date_ouverture_prevue ".$filter_opouvertureprevue." '".$db->idate($filter_dateouvertureprevue_start)."' AND '".$db->idate($filter_dateouvertureprevue_end)."'"; + $sql .= " AND cd.date_ouverture_prevue ".$db->sanitize($filter_opouvertureprevue)." '".$db->idate($filter_dateouvertureprevue_start)."' AND '".$db->idate($filter_dateouvertureprevue_end)."'"; } if (!empty($filter_op1) && $filter_op1 != -1 && $filter_op1 != ' BETWEEN ' && $filter_date1_start != '') { - $sql .= " AND cd.date_ouverture ".$filter_op1." '".$db->idate($filter_date1_start)."'"; + $sql .= " AND cd.date_ouverture ".preg_replace('/[^<>]/', '', $filter_op1)." '".$db->idate($filter_date1_start)."'"; } if (!empty($filter_op1) && $filter_op1 == ' BETWEEN ') { - $sql .= " AND cd.date_ouverture ".$filter_op1." '".$db->idate($filter_date1_start)."' AND '".$db->idate($filter_date1_end)."'"; + $sql .= " AND cd.date_ouverture ".$db->sanitize($filter_op1)." '".$db->idate($filter_date1_start)."' AND '".$db->idate($filter_date1_end)."'"; } if (!empty($filter_op2) && $filter_op2 != -1 && $filter_op2 != ' BETWEEN ' && $filter_date2_start != '') { - $sql .= " AND cd.date_fin_validite ".$filter_op2." '".$db->idate($filter_date2_start)."'"; + $sql .= " AND cd.date_fin_validite ".preg_replace('/[^<>]/', '', $filter_op2)." '".$db->idate($filter_date2_start)."'"; } if (!empty($filter_op2) && $filter_op2 == ' BETWEEN ') { - $sql .= " AND cd.date_fin_validite ".$filter_op2." '".$db->idate($filter_date2_start)."' AND '".$db->idate($filter_date2_end)."'"; + $sql .= " AND cd.date_fin_validite ".$db->sanitize($filter_op2)." '".$db->idate($filter_date2_start)."' AND '".$db->idate($filter_date2_end)."'"; } if (!empty($filter_opcloture) && $filter_opcloture != ' BETWEEN ' && $filter_opcloture != -1 && $filter_datecloture_start != '') { - $sql .= " AND cd.date_cloture ".$filter_opcloture." '".$db->idate($filter_datecloture_start)."'"; + $sql .= " AND cd.date_cloture ".preg_replace('/[^<>]/', '', $filter_opcloture)." '".$db->idate($filter_datecloture_start)."'"; } if (!empty($filter_opcloture) && $filter_opcloture == ' BETWEEN ') { - $sql .= " AND cd.date_cloture ".$filter_opcloture." '".$db->idate($filter_datecloture_start)."' AND '".$db->idate($filter_datecloture_end)."'"; + $sql .= " AND cd.date_cloture ".$db->sanitize($filter_opcloture)." '".$db->idate($filter_datecloture_start)."' AND '".$db->idate($filter_datecloture_end)."'"; } // Add where from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; From 484484ca0b9dbc451e1a3ff1c251d26a85ec0a6b Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 15 Apr 2026 13:50:20 +0200 Subject: [PATCH 03/75] Fix replace js alert with Dolibarr.tools.setEventMessage --- htdocs/core/ajax/objectonoff.php | 10 ++++++++-- htdocs/core/lib/ajax.lib.php | 8 ++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/htdocs/core/ajax/objectonoff.php b/htdocs/core/ajax/objectonoff.php index 5bd06d0a08f..d2b5adf7f40 100644 --- a/htdocs/core/ajax/objectonoff.php +++ b/htdocs/core/ajax/objectonoff.php @@ -42,8 +42,6 @@ if (!defined('NOREQUIRESOC')) { // Load Dolibarr environment require '../../main.inc.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/genericobject.class.php'; - /** * @var Conf $conf * @var DoliDB $db @@ -51,6 +49,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/genericobject.class.php'; * @var Translate $langs * @var User $user */ +require_once DOL_DOCUMENT_ROOT.'/core/class/genericobject.class.php'; $action = GETPOST('action', 'aZ09'); $backtopage = GETPOST('backtopage'); @@ -131,12 +130,19 @@ if (($action == 'set') && !empty($id)) { // Test on permission already done in h foreach ($object->errors as $msg) { print $msg."\n";; } + + $db->close(); + http_response_code(500); exit; } if ($backtopage) { + $db->close(); + header('Location: '.$backtopage); exit; } } + +$db->close(); diff --git a/htdocs/core/lib/ajax.lib.php b/htdocs/core/lib/ajax.lib.php index 980598d8619..ab47f91e300 100644 --- a/htdocs/core/lib/ajax.lib.php +++ b/htdocs/core/lib/ajax.lib.php @@ -843,7 +843,9 @@ function ajax_object_onoff($object, $code, $field, $text_on, $text_off, $input = } }).fail( function(response) { - alert(response.responseText); + //alert(response.responseText); + console.warn(response.responseText); + Dolibarr.tools.setEventMessage(response.responseText, "errors"); } ); }); @@ -886,7 +888,9 @@ function ajax_object_onoff($object, $code, $field, $text_on, $text_off, $input = } }).fail( function(response) { - alert(response.responseText); + //alert(response.responseText); + console.warn(response.responseText); + Dolibarr.tools.setEventMessage(response.responseText, "errors"); } ); }); From 3686e70c1e33714bc22fe385b753cfbd4b449273 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 15 Apr 2026 16:07:59 +0200 Subject: [PATCH 04/75] Doc --- htdocs/core/lib/geturl.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/geturl.lib.php b/htdocs/core/lib/geturl.lib.php index 339abf89c3c..c8df855a399 100644 --- a/htdocs/core/lib/geturl.lib.php +++ b/htdocs/core/lib/geturl.lib.php @@ -30,7 +30,7 @@ * * @param string $url URL to call. * @param string $postorget 'POST', 'GET', 'HEAD', 'PUT', 'PUTALREADYFORMATED', 'POSTALREADYFORMATED', 'DELETE' - * @param string|array $param Parameters of URL (x=value1&y=value2) or may be a formated content with $postorget='PUTALREADYFORMATED' + * @param string|array $param Parameters of URL (x=value1&y=value2) or may be a formatted content with $postorget='PUTALREADYFORMATED' * @param integer $followlocation 0=Do not follow, 1=Follow location. * @param string[] $addheaders Array of string to add into header. Example: ('Accept: application/xrds+xml', ....) * @param string[] $allowedschemes List of schemes that are allowed ('http' + 'https' only by default) From d30da98414328e97dc3df69bfb103369a43d0f54 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 15 Apr 2026 18:40:59 +0200 Subject: [PATCH 05/75] Fix warning --- htdocs/accountancy/journal/bankjournal.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/accountancy/journal/bankjournal.php b/htdocs/accountancy/journal/bankjournal.php index 9a57dbaa93b..05cdfdf861a 100644 --- a/htdocs/accountancy/journal/bankjournal.php +++ b/htdocs/accountancy/journal/bankjournal.php @@ -671,7 +671,7 @@ if (!$error && $action == 'writebookkeeping' && $user->hasRight('accounting', 'b $accountingaccountpayment->fetch(0, getDolGlobalString('SALARIES_ACCOUNTING_ACCOUNT_PAYMENT'), true); $accountingaccountexpensereport = new AccountingAccount($db); - $accountingaccountexpensereport->fetch(0, $conf->global->ACCOUNTING_ACCOUNT_EXPENSEREPORT, true); + $accountingaccountexpensereport->fetch(0, getDolGlobalString('ACCOUNTING_ACCOUNT_EXPENSEREPORT'), true); $accountingaccountsuspense = new AccountingAccount($db); $accountingaccountsuspense->fetch(0, getDolGlobalString('ACCOUNTING_ACCOUNT_SUSPENSE'), true); From a5307001c6444f9d9d21c83b9cba9583eebbb57f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 15 Apr 2026 18:52:59 +0200 Subject: [PATCH 06/75] Make a dangerous and very unstable feature hidden. Should never be on as it ha sno doubt that option is not stable and dev not complete. A lot of side effect not yet managed must be managed first before beeing enabled. Related to #37878 --- htdocs/admin/payment.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/admin/payment.php b/htdocs/admin/payment.php index f60bed8f0c9..fe1111aed8b 100644 --- a/htdocs/admin/payment.php +++ b/htdocs/admin/payment.php @@ -270,12 +270,14 @@ print ' '; print "\n"; // Allow payments on different thirdparties bills but same parent company +/* print ''; print $langs->trans("PaymentOnDifferentThirdBills"); print ''; print $form->selectyesno("FACTURE_PAYMENTS_ON_DIFFERENT_THIRDPARTIES_BILLS", getDolGlobalInt('FACTURE_PAYMENTS_ON_DIFFERENT_THIRDPARTIES_BILLS'), 1); print ''; print "\n"; +*/ // Allow to group payments by mod in rapports print ''; From d6f53cf07892062ba08328749d467569f15afd15 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 15 Apr 2026 18:52:59 +0200 Subject: [PATCH 07/75] Make a dangerous and very unstable feature hidden. Should never be on as it ha sno doubt that option is not stable and dev not complete. A lot of side effect not yet managed must be managed first before beeing enabled. Related to #37878 --- htdocs/admin/payment.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/admin/payment.php b/htdocs/admin/payment.php index 9b380b676b4..19ac365c107 100644 --- a/htdocs/admin/payment.php +++ b/htdocs/admin/payment.php @@ -253,12 +253,14 @@ print ' '; print "\n"; // Allow payments on different thirdparties bills but same parent company +/* print ''; print $langs->trans("PaymentOnDifferentThirdBills"); print ''; print $form->selectyesno("FACTURE_PAYMENTS_ON_DIFFERENT_THIRDPARTIES_BILLS", $conf->global->FACTURE_PAYMENTS_ON_DIFFERENT_THIRDPARTIES_BILLS, 1); print ''; print "\n"; +*/ // Allow to group payments by mod in rapports print ''; From 5d0cd8dd8fc885cb30b8883dba9af01c1d43f3b1 Mon Sep 17 00:00:00 2001 From: Zakaria Boushaba <48571684+Boushabazakaria@users.noreply.github.com> Date: Wed, 15 Apr 2026 19:58:33 +0100 Subject: [PATCH 08/75] Fix: deposit invoice not set as available credit after direct debit payment (#37886) Co-authored-by: Zakaria Boushaba --- htdocs/compta/prelevement/class/bonprelevement.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/compta/prelevement/class/bonprelevement.class.php b/htdocs/compta/prelevement/class/bonprelevement.class.php index 9c0ab968fea..d2f0f904197 100644 --- a/htdocs/compta/prelevement/class/bonprelevement.class.php +++ b/htdocs/compta/prelevement/class/bonprelevement.class.php @@ -690,7 +690,7 @@ class BonPrelevement extends CommonObject $paiement->num_payment = $this->ref; // Set ref of direct debit note $paiement->id_prelevement = $this->id; - $result = $paiement->create($user); // This use ->paiementid, that is ID of payment mode + $result = $paiement->create($user, 1); // This use ->paiementid, that is ID of payment mode. closepaidinvoices=1 to convert deposit invoice to available credit if ($result < 0) { $error++; From 3b8331de7f51d31f7f27f8aa7b6179b1fa74b71d Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Wed, 15 Apr 2026 21:03:26 +0200 Subject: [PATCH 09/75] FIX wrong "REFERENCES" for foreign key of fk_project_task (report this fix in 23 to 24) (#37874) * FIX wrong foreign key for project task (report this fix in 23 to 24) * FIX drop foreign key before drop index * FIX missing install sql file --- htdocs/install/mysql/migration/22.0.0-23.0.0.sql | 8 ++++++-- .../tables/llx_categorie_project_task-project.key.sql | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/htdocs/install/mysql/migration/22.0.0-23.0.0.sql b/htdocs/install/mysql/migration/22.0.0-23.0.0.sql index f1e29481df6..c8f9e2b17df 100644 --- a/htdocs/install/mysql/migration/22.0.0-23.0.0.sql +++ b/htdocs/install/mysql/migration/22.0.0-23.0.0.sql @@ -54,10 +54,14 @@ create table llx_categorie_project_task ( ALTER TABLE llx_categorie_project_task ADD PRIMARY KEY pk_categorie_propal (fk_categorie, fk_project_task); --noqa:enable=PRS ALTER TABLE llx_categorie_project_task ADD INDEX idx_categorie_project_fk_categorie (fk_categorie); -ALTER TABLE llx_categorie_project_task ADD INDEX idx_categorie_project_fk_task (fk_project_task); ALTER TABLE llx_categorie_project_task ADD CONSTRAINT fk_categorie_project_task_categorie_rowid FOREIGN KEY (fk_categorie) REFERENCES llx_categorie (rowid); -ALTER TABLE llx_categorie_project_task ADD CONSTRAINT fk_categorie_project_task_rowid FOREIGN KEY (fk_project_task) REFERENCES llx_projet (rowid); +ALTER TABLE llx_categorie_project_task DROP FOREIGN KEY fk_categorie_project_task_rowid; +-- VMYSQL4.1 DROP INDEX idx_categorie_project_fk_task ON llx_categorie_project_task; +-- VPGSQL8.2 DROP INDEX idx_categorie_project_fk_task; +ALTER TABLE llx_categorie_project_task ADD INDEX idx_categorie_project_fk_task (fk_project_task); +ALTER TABLE llx_categorie_project_task ADD CONSTRAINT fk_categorie_project_task_rowid FOREIGN KEY (fk_project_task) REFERENCES llx_projet_task (rowid); + UPDATE llx_actioncomm SET elementtype = 'project_task' WHERE elementtype = 'task'; diff --git a/htdocs/install/mysql/tables/llx_categorie_project_task-project.key.sql b/htdocs/install/mysql/tables/llx_categorie_project_task-project.key.sql index 44712571a8d..1bf2e33f53d 100644 --- a/htdocs/install/mysql/tables/llx_categorie_project_task-project.key.sql +++ b/htdocs/install/mysql/tables/llx_categorie_project_task-project.key.sql @@ -22,4 +22,4 @@ ALTER TABLE llx_categorie_project_task ADD INDEX idx_categorie_project_fk_catego ALTER TABLE llx_categorie_project_task ADD INDEX idx_categorie_project_fk_task (fk_project_task); ALTER TABLE llx_categorie_project_task ADD CONSTRAINT fk_categorie_project_task_categorie_rowid FOREIGN KEY (fk_categorie) REFERENCES llx_categorie (rowid); -ALTER TABLE llx_categorie_project_task ADD CONSTRAINT fk_categorie_project_task_rowid FOREIGN KEY (fk_project_task) REFERENCES llx_projet (rowid); +ALTER TABLE llx_categorie_project_task ADD CONSTRAINT fk_categorie_project_task_rowid FOREIGN KEY (fk_project_task) REFERENCES llx_projet_task (rowid); From 284190cc10e8005a2234890fda5abb7076d6b7bd Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 16 Apr 2026 13:15:19 +0200 Subject: [PATCH 10/75] Fix select default value missing --- htdocs/public/members/new.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/public/members/new.php b/htdocs/public/members/new.php index 174c4db8f88..8cca1d81aad 100644 --- a/htdocs/public/members/new.php +++ b/htdocs/public/members/new.php @@ -806,6 +806,7 @@ if (getDolGlobalString('MEMBER_SKIP_TABLE') || getDolGlobalString('MEMBER_NEWFOR $morInput.prop({disabled: true, checked: false}); */ $span1.addClass("member-individual-back").removeClass("nonature-back"); $span2.removeClass("member-company-back").addClass("nonature-back"); + $("#phisicalinput").prop("checked", true); $tdLast.addClass("fieldrequired"); $tdFirst.addClass("fieldrequired"); $tdCompany.removeClass("fieldrequired"); @@ -816,6 +817,7 @@ if (getDolGlobalString('MEMBER_SKIP_TABLE') || getDolGlobalString('MEMBER_NEWFOR $morInput.prop({disabled: false, checked: true}); */ $span2.addClass("member-company-back").removeClass("nonature-back"); $span1.removeClass("member-individual-back").addClass("nonature-back"); + $("#moralinput").prop("checked", true); $tdCompany.addClass("fieldrequired"); $tdLast.removeClass("fieldrequired"); $tdFirst.removeClass("fieldrequired"); From 616fe3efe320aa29eb58acc39e06588261b65e6c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 16 Apr 2026 15:19:40 +0200 Subject: [PATCH 11/75] Fix regression on some php versions --- htdocs/core/lib/pdf.lib.php | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/htdocs/core/lib/pdf.lib.php b/htdocs/core/lib/pdf.lib.php index 04b4960a6c6..443e82e6c96 100644 --- a/htdocs/core/lib/pdf.lib.php +++ b/htdocs/core/lib/pdf.lib.php @@ -88,7 +88,7 @@ function pdf_getFormat($outputlangs = null, $mode = 'setup') { global $conf, $db, $langs; - dol_syslog("pdf_getFormat Get paper format with mode=".$mode." MAIN_PDF_FORMAT=".(!getDolGlobalString('MAIN_PDF_FORMAT') ? 'null' : $conf->global->MAIN_PDF_FORMAT)." outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null')." and langs->defaultlang=".(is_object($langs) ? $langs->defaultlang : 'null')); + dol_syslog("pdf_getFormat Get paper format with mode=".$mode." MAIN_PDF_FORMAT=".getDolGlobalString('MAIN_PDF_FORMAT')." outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null')." and langs->defaultlang=".(is_object($langs) ? $langs->defaultlang : 'null')); // Default value if setup was not done and/or entry into c_paper_format not defined $width = 210; @@ -242,7 +242,9 @@ function pdf_getEncryption($pathoffile) //ob_start(); @($parser = new TCPDF_PARSER(ltrim($content))); - [$xref, $data] = $parser->getParsedData(); + $tmp = $parser->getParsedData(); + $xref = $tmp[0]; + $data = $tmp[1] ?? null; unset($parser); //ob_end_clean(); @@ -265,10 +267,8 @@ function pdf_getEncryption($pathoffile) */ function pdf_getPDFFont($outputlangs) { - global $conf; - if (getDolGlobalString('MAIN_PDF_FORCE_FONT')) { - return $conf->global->MAIN_PDF_FORCE_FONT; + return getDolGlobalString('MAIN_PDF_FORCE_FONT'); } $font = 'Helvetica'; // By default, for FPDI, or ISO language on TCPDF @@ -311,8 +311,7 @@ function pdf_getPDFFontSize($outputlangs) */ function pdf_getHeightForLogo($logo, $url = false) { - global $conf; - $height = (!getDolGlobalString('MAIN_DOCUMENTS_LOGO_HEIGHT') ? 20 : $conf->global->MAIN_DOCUMENTS_LOGO_HEIGHT); + $height = getDolGlobalInt('MAIN_DOCUMENTS_LOGO_HEIGHT', 20); $maxwidth = 130; include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; $tmp = dol_getImageSize($logo, $url); @@ -1296,7 +1295,10 @@ function pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_ $pdf->SetDrawColor(224, 224, 224); // Option for footer text color if (getDolGlobalString('PDF_FOOTER_TEXT_COLOR')) { - [$r, $g, $b] = sscanf(getDolGlobalString('PDF_FOOTER_TEXT_COLOR'), '%d, %d, %d'); + $tmparray = sscanf(getDolGlobalString('PDF_FOOTER_TEXT_COLOR'), '%d, %d, %d'); + $r = $tmparray[0]; + $g = $tmparray[1]; + $b = $tmparray[2]; $pdf->SetTextColor($r, $g, $b); } @@ -1334,7 +1336,10 @@ function pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_ // Option for footer background color (without freetext zone) if (getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR')) { - [$r, $g, $b] = sscanf($conf->global->PDF_FOOTER_BACKGROUND_COLOR, '%d, %d, %d'); + $tmparray = sscanf(getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR'), '%d, %d, %d'); + $r = $tmparray[0]; + $g = $tmparray[1]; + $b = $tmparray[2]; $pdf->setAutoPageBreak(false, 0); // Disable auto pagebreak $pdf->Rect(0, $dims['hk'] - $posy + $freetextheight, $dims['wk'] + 1, $marginwithfooter + 1, 'F', array(), $fill_color = array($r, $g, $b)); $pdf->setAutoPageBreak(true, 0); // Restore pagebreak @@ -1386,7 +1391,10 @@ function pdf_pagefoot(&$pdf, $outputlangs, $paramfreetext, $fromcompany, $marge_ // Option for footer background color (without freetext zone) if (getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR')) { - [$r, $g, $b] = sscanf($conf->global->PDF_FOOTER_BACKGROUND_COLOR, '%d, %d, %d'); + $tmparray = sscanf(getDolGlobalString('PDF_FOOTER_BACKGROUND_COLOR'), '%d, %d, %d'); + $r = $tmparray[0]; + $g = $tmparray[1]; + $b = $tmparray[2]; $pdf->setAutoPageBreak(false, 0); // Disable auto pagebreak $pdf->Rect(0, $dims['hk'] - $posy + $freetextheight, $dims['wk'] + 1, $marginwithfooter + 1, 'F', array(), $fill_color = array($r, $g, $b)); $pdf->setAutoPageBreak(true, 0); // Restore pagebreak @@ -1844,7 +1852,8 @@ function pdf_getlinedesc($object, $i, $outputlangs, $hideref = 0, $hidedesc = 0, } if (isset($productCustomerPrice) && !empty($productCustomerPrice->ref_customer)) { - switch ($conf->global->PRODUIT_CUSTOMER_PRICES_PDF_REF_MODE) { + $idcustprice = getDolGlobalInt('PRODUIT_CUSTOMER_PRICES_PDF_REF_MODE'); + switch ($idcustprice) { case 1: $ref_prodserv = $productCustomerPrice->ref_customer; break; From 1abd3d001c1290b94c1aadccb798e76b7d2e226a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 17 Apr 2026 02:18:43 +0200 Subject: [PATCH 12/75] Fix IDOR - Can read ticket even if assigned to another sale representative - Credit by Nguy Minh Tuan - Sun Asterisk --- htdocs/core/lib/security.lib.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/core/lib/security.lib.php b/htdocs/core/lib/security.lib.php index d66feae5592..2e89de5a733 100644 --- a/htdocs/core/lib/security.lib.php +++ b/htdocs/core/lib/security.lib.php @@ -1204,10 +1204,10 @@ function checkUserAccessToObject($user, array $featuresarray, $object = 0, $tabl $sql .= " AND dbt.".$dbt_keyfield." = ".((int) $user->socid); } elseif (isModEnabled("societe") && !$user->hasRight('societe', 'client', 'voir')) { // If internal user without permission to see all thirdparties: Check permission for internal users that are restricted on their objects + if (empty($dbt_keyfield)) { + dol_print_error(null, 'Param dbt_keyfield is required but not defined'); + } if ($feature != 'ticket') { - if (empty($dbt_keyfield)) { - dol_print_error(null, 'Param dbt_keyfield is required but not defined'); - } $sql = "SELECT COUNT(sc.fk_soc) as nb"; $sql .= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt"; $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; @@ -1227,7 +1227,7 @@ function checkUserAccessToObject($user, array $featuresarray, $object = 0, $tabl $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = dbt.".$dbt_keyfield." AND sc.fk_user = ".((int) $user->id); $sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")"; $sql .= " AND dbt.entity IN (".getEntity($sharedelement, 1).")"; - $sql .= " AND (sc.fk_user = ".((int) $user->id)." OR sc.fk_user IS NULL)"; + $sql .= " AND (sc.fk_user = ".((int) $user->id)." OR dbt.".$dbt_keyfield." IS NULL OR dbt.".$dbt_keyfield." = 0)"; } } elseif (isModEnabled('multicompany')) { // If multicompany, and user is an internal user with all permissions, check that object is in correct entity From 841d7cbeacf79e33b32ea772f9292980f4b87fa9 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 17 Apr 2026 04:08:49 +0200 Subject: [PATCH 13/75] Prepare v23 --- ChangeLog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ChangeLog b/ChangeLog index 01f85bf17a6..834cca1e35f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,9 @@ English Dolibarr ChangeLog -------------------------------------------------------------- +***** ChangeLog for 23.0.3 compared to 23.0.2 ***** +SEC: Security fix IDOR on messaging.php - credit Aksoum Abderrahmane + ***** ChangeLog for 23.0.2 compared to 23.0.1 ***** From 557b4244d8fa79f07bdcc30035b5c0376b8f8d63 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 17 Apr 2026 04:09:20 +0200 Subject: [PATCH 14/75] Doc --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 834cca1e35f..41ca2799824 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,7 +3,7 @@ English Dolibarr ChangeLog -------------------------------------------------------------- ***** ChangeLog for 23.0.3 compared to 23.0.2 ***** -SEC: Security fix IDOR on messaging.php - credit Aksoum Abderrahmane +FIX: IDOR on messaging.php - credit Aksoum Abderrahmane ***** ChangeLog for 23.0.2 compared to 23.0.1 ***** From 3d1f01a1fbe7f13a67a4d52b6e6b05f7a6334ce4 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 17 Apr 2026 12:22:47 +0200 Subject: [PATCH 15/75] css --- htdocs/ticket/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/ticket/card.php b/htdocs/ticket/card.php index d2b4f04bc6f..12683d676fc 100644 --- a/htdocs/ticket/card.php +++ b/htdocs/ticket/card.php @@ -962,7 +962,7 @@ if ($action == 'create' || $action == 'presend') { $morehtmlref .= ''; $morehtmlref .= ''; $morehtmlref .= ''; - $morehtmlref .= ''; + $morehtmlref .= ''; $morehtmlref .= ''; } From 4cc3d90cd4e8583ca189877c4ab3687743521d53 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 17 Apr 2026 17:39:17 +0200 Subject: [PATCH 16/75] Fix missing columns --- htdocs/core/lib/project.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/project.lib.php b/htdocs/core/lib/project.lib.php index f0ffcf20e1d..78f393b3e8f 100644 --- a/htdocs/core/lib/project.lib.php +++ b/htdocs/core/lib/project.lib.php @@ -2509,7 +2509,7 @@ function projectLinesPerMonth(&$inc, $firstdaytoshow, $fuser, $parent, $lines, & if ($lines[$i]->id > 0) { //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level); //var_dump($totalforeachday); - $ret = projectLinesPerMonth($inc, $firstdaytoshow, $fuser, $lines[$i]->id, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $isavailable, $oldprojectforbreak, $TWeek); + $ret = projectLinesPerMonth($inc, $firstdaytoshow, $fuser, $lines[$i]->id, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $isavailable, $oldprojectforbreak, $TWeek, $arrayfields); //var_dump('ret with parent='.$lines[$i]->id.' level='.$level); //var_dump($ret); foreach ($ret as $key => $val) { From e578be946134eb0079a8fd4e65abcd7f4734ac05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Fri, 17 Apr 2026 17:51:06 +0200 Subject: [PATCH 17/75] avoid broken link (#37913) * avoid broken link * Update agenda.php --- htdocs/compta/facture/agenda.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/compta/facture/agenda.php b/htdocs/compta/facture/agenda.php index fab5122193b..c9deb9bea20 100644 --- a/htdocs/compta/facture/agenda.php +++ b/htdocs/compta/facture/agenda.php @@ -200,7 +200,7 @@ if ($object->id > 0) { $objthirdparty = $object; $objcon = new stdClass(); - $out = '&origin='.urlencode((string) ($object->element.(property_exists($object, 'module') ? '@'.$object->module : ''))).'&originid='.urlencode((string) ($object->id)); + $out = '&origin='.urlencode((string) ($object->element.(!empty($object->module) ? '@'.$object->module : ''))).'&originid='.urlencode((string) ($object->id)); $urlbacktopage = $_SERVER['PHP_SELF'].'?id='.$object->id; $out .= '&backtopage='.urlencode($urlbacktopage); $permok = $user->hasRight('paymentbagendaybanktransfer', 'myactions', 'create'); From 0f7847afb2178804e43c5b1e991ad09dab87aeea Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 18 Apr 2026 09:01:51 +0200 Subject: [PATCH 18/75] Fix responsive --- htdocs/core/class/html.formsetup.class.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/core/class/html.formsetup.class.php b/htdocs/core/class/html.formsetup.class.php index efbb0283257..45d35afcaca 100644 --- a/htdocs/core/class/html.formsetup.class.php +++ b/htdocs/core/class/html.formsetup.class.php @@ -242,6 +242,7 @@ class FormSetup if ($reshook > 0) { return $hookmanager->resPrint; } else { + $out = '
'; $out = ''; if (empty($hideTitle)) { if (empty($title)) { @@ -265,6 +266,7 @@ class FormSetup $out .= ''; $out .= '
'; + $out .= '
'; return $out; } } From 9525528d84dd609445996cacdd3428947e4fe60c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 18 Apr 2026 09:03:30 +0200 Subject: [PATCH 19/75] Fix --- htdocs/core/class/html.formsetup.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/html.formsetup.class.php b/htdocs/core/class/html.formsetup.class.php index 45d35afcaca..539fc6ee041 100644 --- a/htdocs/core/class/html.formsetup.class.php +++ b/htdocs/core/class/html.formsetup.class.php @@ -243,7 +243,7 @@ class FormSetup return $hookmanager->resPrint; } else { $out = '
'; - $out = ''; + $out .= '
'; if (empty($hideTitle)) { if (empty($title)) { $title = $this->langs->transnoentitiesnoconv("Parameter"); From f1b2dd6481e22cacb561d29ffdcd3a50b618479d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 18 Apr 2026 22:53:59 +0200 Subject: [PATCH 20/75] FIX add permission test on legacy filemanager - Credit Aksoum Abderrahmane --- htdocs/core/filemanagerdol/connectors/php/config.inc.php | 9 ++++++++- htdocs/core/filemanagerdol/connectors/php/connector.php | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/htdocs/core/filemanagerdol/connectors/php/config.inc.php b/htdocs/core/filemanagerdol/connectors/php/config.inc.php index 0704d51f615..7cb8b015ec3 100644 --- a/htdocs/core/filemanagerdol/connectors/php/config.inc.php +++ b/htdocs/core/filemanagerdol/connectors/php/config.inc.php @@ -33,9 +33,9 @@ define('NOTOKENRENEWAL', 1); // Disables token renewal // is a security hole if anybody can access without // being an authenticated user. require_once '../../../../main.inc.php'; - /** * @var Conf $conf + * @var User $user * * @var string $dolibarr_main_data_root * @var string $dolibarr_main_url_root @@ -49,6 +49,13 @@ if ($pos == '/') { //define('DOL_URL_ROOT', $pos); $entity = ((!empty($_SESSION['dol_entity']) && $_SESSION['dol_entity'] > 1) ? $_SESSION['dol_entity'] : null); + +if (!empty($user->admin) && !$user->hasRight('website', 'write')) { + accessforbidden('Need to be admin or having write permission on website module'); + exit; +} + + // SECURITY: You must explicitly enable this "connector". (Set it to "true"). // WARNING: don't just set "$Config['Enabled'] = true ;", you must be sure that only // authenticated users can access this file or use some kind of session checking. diff --git a/htdocs/core/filemanagerdol/connectors/php/connector.php b/htdocs/core/filemanagerdol/connectors/php/connector.php index 25d9312015f..94ea7f864cc 100644 --- a/htdocs/core/filemanagerdol/connectors/php/connector.php +++ b/htdocs/core/filemanagerdol/connectors/php/connector.php @@ -26,6 +26,9 @@ ob_start(); require 'config.inc.php'; // This include the main.inc.php +/** + * @var array $Config + */ require 'connector.lib.php'; if (!$Config['Enabled']) { From 27cbf88c9bd6e436e77d3e3c73d758a137f1aed0 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 20 Apr 2026 12:50:40 +0200 Subject: [PATCH 21/75] Try a fix for #36949 and #37857 --- htdocs/contrat/class/api_contracts.class.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/htdocs/contrat/class/api_contracts.class.php b/htdocs/contrat/class/api_contracts.class.php index 80083fe486e..62df847ce74 100644 --- a/htdocs/contrat/class/api_contracts.class.php +++ b/htdocs/contrat/class/api_contracts.class.php @@ -36,9 +36,7 @@ class Contracts extends DolibarrApi */ public static $FIELDS = array( 'socid', - 'date_contrat', - 'commercial_signature_id', - 'commercial_suivi_id' + 'date_contrat' ); /** From ee3bcd80007a0f222077f625c32693a149039ef0 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 20 Apr 2026 16:47:53 +0200 Subject: [PATCH 22/75] css --- htdocs/website/index.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/website/index.php b/htdocs/website/index.php index 2fed0db1c0d..e838146800e 100644 --- a/htdocs/website/index.php +++ b/htdocs/website/index.php @@ -4162,7 +4162,7 @@ if ($action == 'editcss') { $head = websiteconfigPrepareHead($object); print dol_get_fiche_head($head, 'general', $langs->trans("General"), 0, 'website'); - print ''."\n"; + print ''."\n"; print '
'; // Website @@ -4189,7 +4189,7 @@ if ($action == 'editcss') { $htmltext = ''; print $form->textwithpicto($langs->trans('MainLanguage'), $htmltext, 1, 'help', '', 0, 2, 'WEBSITE_LANG'); print ''; print ''; @@ -4199,7 +4199,7 @@ if ($action == 'editcss') { $htmltext = $langs->trans("Example").': fr,de,sv,it,pt'; print $form->textwithpicto($langs->trans('OtherLanguages'), $htmltext, 1, 'help', '', 0, 2); print ''; print ''; From e88d452eaf3da65867f630b56abd21e363b9f650 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 20 Apr 2026 16:51:32 +0200 Subject: [PATCH 23/75] Doc --- htdocs/core/website.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/website.inc.php b/htdocs/core/website.inc.php index 0097cb3a88c..502ad5968d7 100644 --- a/htdocs/core/website.inc.php +++ b/htdocs/core/website.inc.php @@ -314,7 +314,7 @@ if (!empty($dolibarr_website_allow_custom_php) && $dolibarr_website_allow_custom if (function_exists($systemfunction)) { print '


'; - print 'Website features are protected to be disabled if the PHP system functions ('.implode(',', $systemfunctions).') are not disabled for the website context.
'; + print 'Website features are DISABLED if the PHP system functions ('.implode(',', $systemfunctions).') are NOT disabled for the website context.
'; print 'The value "'.$systemfunction.'" has NOT been found into the current disable_functions=
'; print '
'; - print img_picto('', 'language', 'class="picotfixedwidth"'); + print img_picto('', 'language', 'class="pictofixedwidth"'); print $formadmin->select_language((GETPOSTISSET('WEBSITE_LANG') ? GETPOST('WEBSITE_LANG', 'aZ09comma') : ($object->lang ? $object->lang : '0')), 'WEBSITE_LANG', 0, array(), 1, 0, 0, 'minwidth300', 2, 0, 0, array(), 1); print '
'; - print img_picto('', 'language', 'class="picotfixedwidth"'); + print img_picto('', 'language', 'class="pictofixedwidth"'); print ''; print '