From 1730aa56675b31cfede895fdae55b673d887fb8f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 14 Aug 2026 16:25:46 +0200 Subject: [PATCH 1/6] Fix AISLE-2026-0340-0086 Authorization bypass in clonetasks: private destination project check is inverted - reported by Pavel Kohout --- htdocs/core/actions_massactions.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php index 797b2c77fd4..684698af331 100644 --- a/htdocs/core/actions_massactions.inc.php +++ b/htdocs/core/actions_massactions.inc.php @@ -1946,7 +1946,7 @@ if (!$error && ($massaction == 'clonetasks' || ($action == 'clonetasks' && $conf if (empty($newproject->public)) { $tmps = $newproject->getProjectsAuthorizedForUser($user, 0, 1, 0, '(fk_statut:=:1)'); // We check only open project (cloning on closed is not allowed) $tmparray = explode(',', $tmps); - if (!in_array($newproject->id, $tmparray)) { + if (in_array($newproject->id, $tmparray)) { $iscontactofnewproject = 1; } } From 4da2578588aaae89a9d64c5f95251df84cdb3ad1 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 14 Aug 2026 18:10:58 +0200 Subject: [PATCH 2/6] Fix AISLE-2026-0340-0087 IDOR in user bank account edit flow - reported by Pavel Kohout --- htdocs/user/bank.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/htdocs/user/bank.php b/htdocs/user/bank.php index 6d9117a3cf0..f79a61e8c01 100644 --- a/htdocs/user/bank.php +++ b/htdocs/user/bank.php @@ -99,6 +99,14 @@ if (!$bankid) { $account->fetch(0, '', $id); } else { $account->fetch($bankid); + if ($account->id > 0) { + if ((int) $account->userid !== (int) $object->id) { + accessforbidden(); + } + if ((int) $account->entity !== (int) $conf->entity) { + accessforbidden(); + } + } } if (empty($account->userid)) { $account->userid = $object->id; From 9e385dc0ab15db5491224cc91dc98103ec91753c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 14 Aug 2026 19:45:47 +0200 Subject: [PATCH 3/6] Exclude some keys in api put and post --- htdocs/adherents/class/api_members.class.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/htdocs/adherents/class/api_members.class.php b/htdocs/adherents/class/api_members.class.php index c8462e36db8..a4a45b3c5d2 100644 --- a/htdocs/adherents/class/api_members.class.php +++ b/htdocs/adherents/class/api_members.class.php @@ -424,6 +424,10 @@ class Members extends DolibarrApi } foreach ($request_data as $field => $value) { + if (in_array($field, array('pass', 'pass_crypted', 'pass_indatabase', 'pass_indatabase_crypted', 'pass_temp', 'api_key'))) { + // This properties can't be set/modified with API + throw new RestException(405, 'The property '.$field." can't be set/modified using the APIs"); + } if ($field == 'id') { continue; } From 52d83c89d605de2e30adbfb2b805f5e26ecd1f07 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 14 Aug 2026 19:47:17 +0200 Subject: [PATCH 4/6] Disqualified some fields from api --- htdocs/adherents/class/api_members.class.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/htdocs/adherents/class/api_members.class.php b/htdocs/adherents/class/api_members.class.php index a4a45b3c5d2..317df08dcce 100644 --- a/htdocs/adherents/class/api_members.class.php +++ b/htdocs/adherents/class/api_members.class.php @@ -380,6 +380,10 @@ class Members extends DolibarrApi $member = new Adherent($this->db); foreach ($request_data as $field => $value) { + if (in_array($field, array('pass', 'pass_crypted', 'pass_indatabase', 'pass_indatabase_crypted', 'pass_temp', 'api_key'))) { + // This properties can't be set/modified with API + throw new RestException(405, 'The property '.$field." can't be set/modified using the APIs"); + } if ($field === 'caller') { // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again with the caller $member->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09'); @@ -569,6 +573,9 @@ class Members extends DolibarrApi unset($object->fk_delivery_address); unset($object->shipping_method_id); + unset($object->pass); + unset($object->pass_crypted); + unset($object->total_ht); unset($object->total_ttc); unset($object->total_tva); From fbf476cc5d9a21b16bfa04ab17d4e84eda38d7ce Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 14 Aug 2026 20:00:37 +0200 Subject: [PATCH 5/6] Restrict some field in api create/update of member for secure purpose - reported by vulncheck --- htdocs/adherents/class/api_members.class.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/htdocs/adherents/class/api_members.class.php b/htdocs/adherents/class/api_members.class.php index 317df08dcce..05ddabc1cb6 100644 --- a/htdocs/adherents/class/api_members.class.php +++ b/htdocs/adherents/class/api_members.class.php @@ -384,6 +384,10 @@ class Members extends DolibarrApi // This properties can't be set/modified with API throw new RestException(405, 'The property '.$field." can't be set/modified using the APIs"); } + if (in_array($field, array('user_id') && !DolibarrApiAccess::$user->hasRight('user', 'user', 'creer'))) { + // This properties can't be set/modified with API without permission user->user->creer + throw new RestException(405, 'The property '.$field." can't be set/modified using the APIs without permission user->user->create"); + } if ($field === 'caller') { // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again with the caller $member->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09'); @@ -427,11 +431,17 @@ class Members extends DolibarrApi throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } + $sav_user_id = $member->user_id; + foreach ($request_data as $field => $value) { if (in_array($field, array('pass', 'pass_crypted', 'pass_indatabase', 'pass_indatabase_crypted', 'pass_temp', 'api_key'))) { // This properties can't be set/modified with API throw new RestException(405, 'The property '.$field." can't be set/modified using the APIs"); } + if (in_array($field, array('user_id') && !DolibarrApiAccess::$user->hasRight('user', 'user', 'creer'))) { + // This properties can't be set/modified with API without permission user->user->creer + throw new RestException(405, 'The property '.$field." can't be set/modified using the APIs without the permission user->user->create"); + } if ($field == 'id') { continue; } @@ -472,7 +482,9 @@ class Members extends DolibarrApi // If there is no error, update() returns the number of affected rows // so if the update is a no op, the return value is zero. - if ($member->update(DolibarrApiAccess::$user) >= 0) { + $nosyncuser = 0; + $nosyncpassword = 1; // Disable password sync. Management of password must be done using the user API only. + if ($member->update(DolibarrApiAccess::$user, 0, $nosyncuser, $nosyncpassword) >= 0) { return $this->get($id); } else { throw new RestException(500, 'Error when updating member: '.$member->error); From 2d765488acb3f61cc9ebf65969df4bb83df2da15 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 14 Aug 2026 20:08:48 +0200 Subject: [PATCH 6/6] Clean url --- htdocs/core/lib/ticket.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/ticket.lib.php b/htdocs/core/lib/ticket.lib.php index 0cbc6e9c326..850d4e72fcf 100644 --- a/htdocs/core/lib/ticket.lib.php +++ b/htdocs/core/lib/ticket.lib.php @@ -218,7 +218,7 @@ function showDirectPublicLink($object) $email = CMailFile::getValidAddress($object->origin_email, 2); $url = ''; if ($email) { - $url = getDolGlobalString('TICKET_URL_PUBLIC_INTERFACE', dol_buildpath('/public/ticket/', 3)).'view.php?track_id='.$object->track_id.'&email='.$email; + $url = getDolGlobalString('TICKET_URL_PUBLIC_INTERFACE', dol_buildpath('/public/ticket/', 3)).'view.php?track_id='.urlencode($object->track_id).'&email='.urlencode($email); } $out = '';