Fix: Avoid double escapes in sql values (#38940)

* Fix: values already escaped for db in 'isInDb'

# Fix: values already escaped for db in 'isInDb'

The values of $value_arr were escaped before the call to 'isInDb' resulting
in a potential double escape'

* Fix: escape values only once in sqlFilterSearchField

# Fix: escape values only once in sqlFilterSearchField

The values of $value were escaped before appending them to the sql expression where they were also escaped, resulting in a potential double escape'

* Fix: escape values only once in sqlFilterSearchField

# Fix: escape values only once in sqlFilterSearchField

The values of $value were escaped before appending them to the sql expression where they were also escaped, resulting in a potential double escape'

* Fix: escape values only once in getOptions

# Fix: escape values only once in getOptions

The values of $selectedValues were escaped before appending them to the sql expression where they were also escaped, resulting in a potential double escape'

* Fix: escape values only once in sqlFilterSearchField

# Fix: escape values only once in sqlFilterSearchField

The values of $value were escaped before appending them to the sql expression where they were also escaped, resulting in a potential double escape'

* Fix: escape values only once in sqlFilterSearchField

# Fix: escape values only once in sqlFilterSearchField

The values of $value were escaped before appending them to the sql expression where they were also escaped, resulting in a potential double escape'

* Fix: escape values only once in sqlFilterSearchField

# Fix: escape values only once in sqlFilterSearchField

The values of $value were escaped before appending them to the sql expression where they were also escaped, resulting in a potential double escape'

---------

Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
This commit is contained in:
MDW 2026-06-21 23:03:22 +02:00 committed by GitHub
parent 65a0d0e36e
commit 4eaa846739
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 76 additions and 38 deletions

View file

@ -99,7 +99,7 @@ abstract class CommonObject
public $warning;
/**
* @var string[] Array of warning strings
* @var string[] Array of warning strings
*/
public $warnings = array();
@ -7677,7 +7677,7 @@ abstract class CommonObject
$sanitizedGeoDataType = ExtraFields::$geoDataTypes[$attributeType] ?? null;
if ($this->array_options["options_".$key] === null) {
$sql = "UPDATE ".$this->db->prefix().$this->db->sanitize($table_element)."_extrafields";
$sql.= " SET ".$this->db->sanitize($key)." = null";
$sql .= " SET ".$this->db->sanitize($key)." = null";
} elseif (!empty($sanitizedGeoDataType['ST_Function'])) {
$sql = "UPDATE ".$this->db->prefix().$this->db->sanitize($table_element)."_extrafields";
$sql .= " SET ".$this->db->sanitize($key)." = ".$this->db->sanitize($sanitizedGeoDataType['ST_Function'])."('".$this->db->escape($this->array_options["options_".$key])."')";
@ -9482,7 +9482,6 @@ abstract class CommonObject
$param_list = array_keys($param['options']);
$InfoFieldList = explode(":", $param_list[0]);
$value_arr = explode(',', $fieldValue);
$value_arr = array_map(array($this->db, 'escape'), $value_arr);
$selectkey = "rowid";
if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
@ -9603,7 +9602,7 @@ abstract class CommonObject
} elseif (($mode == 'edit') && !in_array(abs($visibility), array(1, 3, 4))) {
// We need to make sure, that the values of hidden extrafields are also part of $_POST. Otherwise, they would be empty after an update of the object. See also getOptionalsFromPost
$ef_name = 'options_' . $key;
$ef_value = $this->array_options[$ef_name]??'';
$ef_value = $this->array_options[$ef_name] ?? '';
$out .= '<input type="hidden" name="' . $ef_name . '" id="' . $ef_name . '" value="' . $ef_value . '" />' . "\n";
continue; // <> -1 and <> 1 and <> 3 = not visible on forms, only on list and <> 4 = not visible at the creation
} elseif ($mode == 'view' && empty($visibility)) {

View file

@ -1,5 +1,6 @@
<?php
/* Copyright (C) 2025 Open-Dsi <support@open-dsi.fr>
* Copyright (C) 2026 MDW <mdeweerd@users.noreply.github.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -70,9 +71,11 @@ class CheckboxField extends CommonSelectField
$moreCss = $this->getInputCss($fieldInfos, $moreCss);
$moreAttrib = trim((string) $moreAttrib);
if (empty($moreAttrib)) $moreAttrib = ' ' . $moreAttrib;
if (empty($moreAttrib)) {
$moreAttrib = ' ' . $moreAttrib;
}
$htmlName = $keyPrefix . $key . $keySuffix;
$values = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value: array($value)));
$values = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value : array($value)));
$optionsList = array();
$options = $this->getOptions($fieldInfos, $key);
@ -95,7 +98,7 @@ class CheckboxField extends CommonSelectField
public function printOutputField($fieldInfos, $key, $value, $keyPrefix = '', $keySuffix = '', $moreCss = '', $moreAttrib = '')
{
global $langs;
$values = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value: array($value)));
$values = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value : array($value)));
$out = '';
if (!$this->isEmptyValue($fieldInfos, $values)) {
@ -147,7 +150,7 @@ class CheckboxField extends CommonSelectField
public function verifyFieldValue($fieldInfos, $key, $value)
{
global $langs;
$values = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value: array($value)));
$values = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value : array($value)));
$result = parent::verifyFieldValue($fieldInfos, $key, $values);
if ($result && !$this->isEmptyValue($fieldInfos, $values)) {
@ -201,7 +204,9 @@ class CheckboxField extends CommonSelectField
if (GETPOSTISSET($htmlName)) {
$values = GETPOST($htmlName, 'array');
if (is_array($values)) $values = implode(',', $values);
if (is_array($values)) {
$values = implode(',', $values);
}
} else {
$values = $defaultValue;
}
@ -249,7 +254,8 @@ class CheckboxField extends CommonSelectField
$field = $this->db->sanitize($alias . ($fieldInfos->nameInTable ?? $key));
$sanitizedSqlIn = "'" . implode("','", array_map(array($this->db, 'escape'), $value)) . "'";
return " AND " . $field . " IN (" . $sanitizedSqlIn . ")";
$sqlPartialCond = " AND " . $field . " IN (" . $sanitizedSqlIn . ")";
return $sqlPartialCond;
}
return '';

View file

@ -1,5 +1,6 @@
<?php
/* Copyright (C) 2025 Open-Dsi <support@open-dsi.fr>
* Copyright (C) 2026 MDW <mdeweerd@users.noreply.github.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -53,9 +54,11 @@ class ChkbxlstField extends CommonSellistField
$moreCss = $this->getInputCss($fieldInfos, $moreCss);
$moreAttrib = trim((string) $moreAttrib);
if (empty($moreAttrib)) $moreAttrib = ' ' . $moreAttrib;
if (empty($moreAttrib)) {
$moreAttrib = ' ' . $moreAttrib;
}
$htmlName = $keyPrefix . $key . $keySuffix;
$values = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value: array($value)));
$values = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value : array($value)));
$optionsList = array();
$options = $this->getOptions($fieldInfos, $key);
@ -84,9 +87,11 @@ class ChkbxlstField extends CommonSellistField
$moreCss = $this->getInputCss($fieldInfos, $moreCss);
$moreAttrib = trim((string) $moreAttrib);
if (empty($moreAttrib)) $moreAttrib = ' ' . $moreAttrib;
if (empty($moreAttrib)) {
$moreAttrib = ' ' . $moreAttrib;
}
$htmlName = $keyPrefix . $key . $keySuffix;
$values = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value: array($value)));
$values = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value : array($value)));
$options = $this->getOptions($fieldInfos, $key);
@ -107,7 +112,7 @@ class ChkbxlstField extends CommonSellistField
*/
public function printOutputField($fieldInfos, $key, $value, $keyPrefix = '', $keySuffix = '', $moreCss = '', $moreAttrib = '')
{
$values = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value: array($value)));
$values = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value : array($value)));
$out = '';
if (!$this->isEmptyValue($fieldInfos, $values)) {
@ -167,7 +172,7 @@ class ChkbxlstField extends CommonSellistField
*/
public function verifyFieldValue($fieldInfos, $key, $value)
{
$values = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value: array($value)));
$values = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value : array($value)));
$result = parent::verifyFieldValue($fieldInfos, $key, $values);
if ($result && !$this->isEmptyValue($fieldInfos, $values)) {
@ -217,7 +222,9 @@ class ChkbxlstField extends CommonSellistField
if (GETPOSTISSET($htmlName)) {
$values = GETPOST($htmlName, 'array');
if (is_array($values)) $values = implode(',', $values);
if (is_array($values)) {
$values = implode(',', $values);
}
} else {
$values = $defaultValue;
}
@ -264,8 +271,9 @@ class ChkbxlstField extends CommonSellistField
$alias = $fieldInfos->sqlAlias ?? 't.';
$field = $this->db->sanitize($alias . ($fieldInfos->nameInTable ?? $key));
$tmp = "'" . implode("','", array_map(array($this->db, 'escape'), $value)) . "'";
return " AND " . $field . " IN (" . $this->db->sanitize($tmp, 1) . ")";
$sanitizedSqlIn = "'" . implode("','", array_map(array($this->db, 'escape'), $value)) . "'";
$sqlPartialCond = " AND " . $field . " IN (" . $sanitizedSqlIn . ")";
return $sqlPartialCond;
}
return '';

View file

@ -1,5 +1,6 @@
<?php
/* Copyright (C) 2025 Open-Dsi <support@open-dsi.fr>
* Copyright (C) 2026 MDW <mdeweerd@users.noreply.github.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -128,7 +129,9 @@ class CommonSellistField extends CommonField
$labelAlias[] = $tmp['alias'];
}
$keyField = (string) ($InfoFieldList[2] ?? '');
if (empty($keyField)) $keyField = 'rowid';
if (empty($keyField)) {
$keyField = 'rowid';
}
$keyFieldParent = (string) ($InfoFieldList[3] ?? '');
$tmp = array_map('trim', explode('|', $keyFieldParent));
$parentName = (string) ($tmp[0] ?? '');
@ -302,8 +305,8 @@ class CommonSellistField extends CommonField
}
// Only selected values
if (!empty($selectedValues)) {
$tmp = "'" . implode("','", array_map(array($this->db, 'escape'), $selectedValues)) . "'";
$sql .= " AND " . $this->db->sanitize($keyField) . " IN (" . $this->db->sanitize($tmp, 1) . ")";
$sanitizedSqlIn = "'" . implode("','", array_map(array($this->db, 'escape'), $selectedValues)) . "'";
$sql .= " AND " . $this->db->sanitize($keyField) . " IN (" . $sanitizedSqlIn . ")";
}
// Note: $InfoFieldList can be 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter[:CategoryIdType[:CategoryIdList[:Sortfield]]]]]]'

View file

@ -1,5 +1,6 @@
<?php
/* Copyright (C) 2025 Open-Dsi <support@open-dsi.fr>
* Copyright (C) 2026 MDW <mdeweerd@users.noreply.github.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -53,9 +54,11 @@ class RadioField extends CommonSelectField
$moreCss = $this->getInputCss($fieldInfos, $moreCss);
$moreAttrib = trim((string) $moreAttrib);
if (empty($moreAttrib)) $moreAttrib = ' ' . $moreAttrib;
if (empty($moreAttrib)) {
$moreAttrib = ' ' . $moreAttrib;
}
$htmlName = $keyPrefix . $key . $keySuffix;
$value = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value: array($value)));
$value = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value : array($value)));
$optionsList = array();
$options = $this->getOptions($fieldInfos, $key);
@ -82,7 +85,9 @@ class RadioField extends CommonSelectField
{
$moreCss = $this->getInputCss($fieldInfos, $moreCss);
$moreAttrib = trim((string) $moreAttrib);
if (empty($moreAttrib)) $moreAttrib = ' ' . $moreAttrib;
if (empty($moreAttrib)) {
$moreAttrib = ' ' . $moreAttrib;
}
$htmlName = $keyPrefix . $key . $keySuffix;
$selectedValue = $this->isEmptyValue($fieldInfos, $value) ? '' : (string) $value;
@ -253,8 +258,9 @@ class RadioField extends CommonSelectField
$alias = $fieldInfos->sqlAlias ?? 't.';
$field = $this->db->sanitize($alias . ($fieldInfos->nameInTable ?? $key));
$tmp = "'" . implode("','", array_map(array($this->db, 'escape'), $value)) . "'";
return " AND " . $field . " IN (" . $this->db->sanitize($tmp, 1) . ")";
$sanitizedSqlIn = "'" . implode("','", array_map(array($this->db, 'escape'), $value)) . "'";
$sqlPartialCond = " AND " . $field . " IN (" . $sanitizedSqlIn . ")";
return $sqlPartialCond;
}
return '';

View file

@ -1,5 +1,6 @@
<?php
/* Copyright (C) 2025 Open-Dsi <support@open-dsi.fr>
* Copyright (C) 2026 MDW <mdeweerd@users.noreply.github.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -53,9 +54,11 @@ class SelectField extends CommonSelectField
$moreCss = $this->getInputCss($fieldInfos, $moreCss);
$moreAttrib = trim((string) $moreAttrib);
if (empty($moreAttrib)) $moreAttrib = ' ' . $moreAttrib;
if (empty($moreAttrib)) {
$moreAttrib = ' ' . $moreAttrib;
}
$htmlName = $keyPrefix . $key . $keySuffix;
$value = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value: array($value)));
$value = $this->isEmptyValue($fieldInfos, $value) ? array() : (is_string($value) ? explode(',', $value) : (is_array($value) ? $value : array($value)));
$optionsList = array();
$options = $this->getOptions($fieldInfos, $key);
@ -82,9 +85,13 @@ class SelectField extends CommonSelectField
{
$moreCss = $this->getInputCss($fieldInfos, $moreCss);
$moreAttrib = trim((string) $moreAttrib);
if (empty($moreAttrib)) $moreAttrib = ' ' . $moreAttrib;
if (empty($moreAttrib)) {
$moreAttrib = ' ' . $moreAttrib;
}
$placeHolder = $fieldInfos->inputPlaceholder;
if (!empty($placeHolder)) $placeHolder = ' placeholder="' . dolPrintHTMLForAttribute($placeHolder) . '"';
if (!empty($placeHolder)) {
$placeHolder = ' placeholder="' . dolPrintHTMLForAttribute($placeHolder) . '"';
}
$autoFocus = $fieldInfos->inputAutofocus ? ' autofocus' : '';
$htmlName = $keyPrefix . $key . $keySuffix;
@ -248,8 +255,9 @@ class SelectField extends CommonSelectField
$alias = $fieldInfos->sqlAlias ?? 't.';
$field = $this->db->sanitize($alias . ($fieldInfos->nameInTable ?? $key));
$tmp = "'" . implode("','", array_map(array($this->db, 'escape'), $value)) . "'";
return " AND " . $field . " IN (" . $this->db->sanitize($tmp, 1) . ")";
$sanitizedSqlIn = "'" . implode("','", array_map(array($this->db, 'escape'), $value)) . "'";
$sqlPartialCond = " AND " . $field . " IN (" . $sanitizedSqlIn . ")";
return $sqlPartialCond;
}
return '';

View file

@ -1,5 +1,6 @@
<?php
/* Copyright (C) 2025 Open-Dsi <support@open-dsi.fr>
* Copyright (C) 2026 MDW <mdeweerd@users.noreply.github.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -53,7 +54,9 @@ class SellistField extends CommonSellistField
$moreCss = $this->getInputCss($fieldInfos, $moreCss);
$moreAttrib = trim((string) $moreAttrib);
if (empty($moreAttrib)) $moreAttrib = ' ' . $moreAttrib;
if (empty($moreAttrib)) {
$moreAttrib = ' ' . $moreAttrib;
}
$htmlName = $keyPrefix . $key . $keySuffix;
$optionsList = array();
@ -83,9 +86,13 @@ class SellistField extends CommonSellistField
$moreCss = $this->getInputCss($fieldInfos, $moreCss);
$moreAttrib = trim((string) $moreAttrib);
if (empty($moreAttrib)) $moreAttrib = ' ' . $moreAttrib;
if (empty($moreAttrib)) {
$moreAttrib = ' ' . $moreAttrib;
}
$placeHolder = $fieldInfos->inputPlaceholder;
if (!empty($placeHolder)) $placeHolder = ' placeholder="' . dolPrintHTMLForAttribute($placeHolder) . '"';
if (!empty($placeHolder)) {
$placeHolder = ' placeholder="' . dolPrintHTMLForAttribute($placeHolder) . '"';
}
$autoFocus = $fieldInfos->inputAutofocus ? ' autofocus' : '';
$htmlName = $keyPrefix . $key . $keySuffix;
$selectedValue = is_null($value) || $this->isEmptyValue($fieldInfos, $value) ? '' : (string) $value;
@ -274,8 +281,9 @@ class SellistField extends CommonSellistField
$alias = $fieldInfos->sqlAlias ?? 't.';
$field = $this->db->sanitize($alias . ($fieldInfos->nameInTable ?? $key));
$tmp = "'" . implode("','", array_map(array($this->db, 'escape'), $value)) . "'";
return " AND " . $field . " IN (" . $this->db->sanitize($tmp, 1) . ")";
$sanitizedSqlIn = "'" . implode("','", array_map(array($this->db, 'escape'), $value)) . "'";
$sqlPartialCond = " AND " . $field . " IN (" . $sanitizedSqlIn . ")";
return $sqlPartialCond;
}
return '';