CVE-2022-0819 (PHP, published 2022-03-02T16:15Z)
Description: value: Code Injection in GitHub repository dolibarr/dolibarr prior to 15.0.1.
Severity: MEDIUM (CVSS v3 base score: 8.8)
Weakness: NVD-CWE-Other \u2014 Other
NVD is only using a subset of CWE for mapping instead of the entire CWE, and the weakness type is not covered by that subset.
Repository: https://github.com/dolibarr/dolibarr
Files changed:
htdocs/admin/emailcollector_list.php
htdocs/admin/mails_templates.php
htdocs/admin/menus/edit.php
htdocs/bom/bom_list.php
htdocs/compta/cashcontrol/cashcontrol_list.php
htdocs/compta/facture/list.php
htdocs/compta/resultat/result.php
htdocs/core/boxes/box_scheduled_jobs.php
htdocs/core/class/commonobject.class.php
htdocs/core/class/extrafields.class.php
htdocs/core/class/html.form.class.php
htdocs/core/class/html.formother.class.php
htdocs/core/class/menu.class.php
htdocs/core/class/translate.class.php
htdocs/core/customreports.php
htdocs/core/lib/functions.lib.php
htdocs/core/tpl/admin_extrafields_view.tpl.php
htdocs/core/tpl/extrafields_list_array_fields.tpl.php
htdocs/core/tpl/extrafields_list_print_fields.tpl.php
htdocs/eventorganization/conferenceorbooth_list.php
htdocs/eventorganization/conferenceorboothattendee_list.php
htdocs/hrm/evaluation_list.php
htdocs/hrm/job_list.php
htdocs/hrm/position.php
htdocs/hrm/position_list.php
htdocs/hrm/skill_card.php
htdocs/hrm/skill_list.php
htdocs/knowledgemanagement/knowledgerecord_list.php
htdocs/mrp/mo_list.php
htdocs/partnership/partnership_list.php
htdocs/product/inventory/list.php
htdocs/product/list.php
htdocs/product/stock/list.php
htdocs/product/stock/productlot_list.php
htdocs/projet/class/task.class.php
htdocs/projet/list.php
htdocs/recruitment/recruitmentcandidature_list.php
htdocs/recruitment/recruitmentjobposition_list.php
htdocs/salaries/list.php
htdocs/salaries/payments.php
htdocs/ticket/list.php
htdocs/workstation/workstation_list.php
test/phpunit/SecurityTest.php
Commit message: Fix #hunterb03d4415-d4f9-48c8-9ae2-d3aa248027b5

Vulnerable code:
		$visible = dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
				if (!dol_eval($obj->enabled, 1)) {
	print ', '.$langs->trans("Example").': fk_mainmenu=abc&fk_leftmenu=def';
		print ' ('.$langs->trans("ConditionIsCurrently").': '.yn(dol_eval($menu->enabled, 1)).')';
		print ' ('.$langs->trans("ConditionIsCurrently").': '.yn(dol_eval($menu->perms, 1)).')';
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
				'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
				$r = dol_eval($result, 1);
				$r = dol_eval($result, 1);
						$r = dol_eval($result, 1);
						$r = dol_eval($result, 1);
					if (dol_eval($objp->test, 1, 1)) {
				$enabled = dol_eval($this->fields[$key]['enabled'], 1);
				$perms = dol_eval($this->fields[$key]['perms'], 1);
								$this->array_options["options_".$key] = dol_eval($extrafields->attributes[$this->table_element]['computed'][$key], 1, 0);
						$value = dol_eval($attrfieldcomputed, 1, 0);
					$value = dol_eval($attrfieldcomputed, 1, 0);
			$value = dol_eval($computed, 1, 0);
						$enabled = dol_eval($extrafields->attributes[$this->table_element]['enabled'][$key], 1);
						$visibility = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1);
						$perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1);
			$perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1);
			$list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1);
			$perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1);
			$list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1);
					$enabled = dol_eval($this->attributes[$object->table_element]['enabled'][$key], 1);
					$visibility = dol_eval($this->attributes[$object->table_element]['list'][$key], 1);
					$perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1);
				if (!dol_eval($val['enabled'], 1, 1)) {
				if (isset($val['enabled']) && !dol_eval($val['enabled'], 1)) {
				if (isset($val['visible']) && !dol_eval($val['visible'], 1)) {
				if (isset($val['enabled']) && !dol_eval($val['enabled'], 1)) {
				if (isset($val['visible']) && !dol_eval($val['visible'], 1)) {
			//if (dol_eval($val['enabled'], 1)) $nb++;
			//if ($key[0] == '$') { return dol_eval($key,1); }
				return dol_eval($key, 1);
	if (dol_eval($val['enabled'], 1)) {
	if (!empty($val['isameasure']) && (!isset($val['enabled']) || dol_eval($val['enabled'], 1))) {
		if (!empty($extrafields->attributes[$object->table_element]['totalizable'][$key]) && (!isset($extrafields->attributes[$object->table_element]['enabled'][$key]) || dol_eval($extrafields->attributes[$object->table_element]['enabled'][$key], 1))) {
		if (empty($val['measure']) && (!isset($val['enabled']) || dol_eval($val['enabled'], 1))) {
				if (!empty($extrafields->attributes[$object->table_element]['totalizable'][$key]) && (!isset($extrafields->attributes[$object->table_element]['enabled'][$key]) || dol_eval($extrafields->attributes[$object->table_element]['enabled'][$key], 1))) {
 * @param 	string	$s				String to evaluate
 * @param	int		$returnvalue	0=No return (used to execute eval($a=something)). 1=Value of eval is returned (used to eval($something)).
 * @param   int     $hideerrors     1=Hide errors
 * @return	mixed					Nothing or return result of eval
function dol_eval($s, $returnvalue = 0, $hideerrors = 1)
	// Replace dangerous char (used for RCE), we allow only PHP variable testing.
		return 'Bad string syntax to evaluate: '.$s;
	$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "unlink", "mkdir", "rmdir", "symlink", "touch", "umask"));
		/*if (! dol_eval($extrafields->attributes[$elementtype]['enabled'][$key], 1)) {
					'checked'  => ((dol_eval($extrafields->attributes[$extrafieldsobjectkey]['list'][$key], 1) <= 0) ? 0 : 1),
					'enabled'  => (abs((int) $extrafields->attributes[$extrafieldsobjectkey]['list'][$key]) != 3 && dol_eval($extrafields->attributes[$extrafieldsobjectkey]['perms'][$key], 1)),
					$value = dol_eval($extrafields->attributes[$extrafieldsobjectkey]['computed'][$key], 1);
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
			$visible = (int) dol_eval($val['visible'], 1);
				'enabled' => ($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
			$visible = (int) dol_eval($val['visible'], 1);
				'enabled' => ($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$visible = (int) dol_eval($val['visible'], 1);
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
	'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1)),
		$result=dol_eval('(($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref: "Parent project not found"', 1, 1);
		$result=dol_eval('$a=function() { }; $a;', 1, 1);

Fixed code:
		$visible = dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
				if (!dol_eval($obj->enabled, 1, 1, '1')) {
	print ', <span class="opacitymedium">'.$langs->trans("Example").': fk_mainmenu=abc&fk_leftmenu=def</span>';
		print ' <span class="opacitymedium">('.$langs->trans("ConditionIsCurrently").':</span> '.yn(dol_eval($menu->enabled, 1, 1, '1')).')';
		print ' <span class="opacitymedium">('.$langs->trans("ConditionIsCurrently").':</span> '.yn(dol_eval($menu->perms, 1, 1, '1')).')';
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
				'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
				$r = dol_eval($result, 1, 1, '1');
				$r = dol_eval($result, 1, 1, 1);
						$r = dol_eval($result, 1, 1, 1);
						$r = dol_eval($result, 1, 1, 1);
					if (dol_eval($objp->test, 1, 1, '')) {
				$enabled = dol_eval($this->fields[$key]['enabled'], 1, 1, '1');
				$perms = dol_eval($this->fields[$key]['perms'], 1, 1, '1');
								$this->array_options["options_".$key] = dol_eval($extrafields->attributes[$this->table_element]['computed'][$key], 1, 0, '');
						$value = dol_eval($attrfieldcomputed, 1, 0, '');
					$value = dol_eval($attrfieldcomputed, 1, 0, '');
			$value = dol_eval($computed, 1, 0, '');
						$enabled = dol_eval($extrafields->attributes[$this->table_element]['enabled'][$key], 1, 1, '1');
						$visibility = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1, 1, '1');
						$perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1, 1, '1');
			$perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '1');
			$list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '1');
			$perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '1');
			$list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '1');
					$enabled = dol_eval($this->attributes[$object->table_element]['enabled'][$key], 1, 1, '1');
					$visibility = dol_eval($this->attributes[$object->table_element]['list'][$key], 1, 1, '1');
					$perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1, 1, '1');
				if (!dol_eval($val['enabled'], 1, 1, 1, '1')) {
				if (isset($val['enabled']) && !dol_eval($val['enabled'], 1, 1, '1')) {
				if (isset($val['visible']) && !dol_eval($val['visible'], 1, 1, '1')) {
				if (isset($val['enabled']) && !dol_eval($val['enabled'], 1, 1, '1')) {
				if (isset($val['visible']) && !dol_eval($val['visible'], 1, 1, '1')) {
			//if (dol_eval($val['enabled'], 1, 1, '1')) $nb++;
			//if ($key[0] == '$') { return dol_eval($key, 1, 1, '1'); }
				return dol_eval($key, 1, 1, '1');
	if (dol_eval($val['enabled'], 1, 1, '1')) {
	if (!empty($val['isameasure']) && (!isset($val['enabled']) || dol_eval($val['enabled'], 1, 1, '1'))) {
		if (!empty($extrafields->attributes[$object->table_element]['totalizable'][$key]) && (!isset($extrafields->attributes[$object->table_element]['enabled'][$key]) || dol_eval($extrafields->attributes[$object->table_element]['enabled'][$key], 1, 1, '1'))) {
		if (empty($val['measure']) && (!isset($val['enabled']) || dol_eval($val['enabled'], 1, 1, '1'))) {
				if (!empty($extrafields->attributes[$object->table_element]['totalizable'][$key]) && (!isset($extrafields->attributes[$object->table_element]['enabled'][$key]) || dol_eval($extrafields->attributes[$object->table_element]['enabled'][$key], 1, 1, '1'))) {
 * @param 	string	$s					String to evaluate
 * @param	int		$returnvalue		0=No return (used to execute eval($a=something)). 1=Value of eval is returned (used to eval($something)).
 * @param   int     $hideerrors     	1=Hide errors
 * @param	string	$onlysimplestring	Accept only simple string with char 'a-z0-9\s$_->&|=';
 * @return	mixed						Nothing or return result of eval
function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1')
	// Test dangerous char (used for RCE), we allow only PHP variable testing.
	if ($onlysimplestring == '1') {
		//print preg_quote('$_->&|', '/');
		if (preg_match('/[^a-z0-9\s'.preg_quote('$_->&|=', '/').']/i', $s)) {
			return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
		}
	}
		return 'Bad string syntax to evaluate (backtick char is forbidden): '.$s;
	}
	if (strpos($s, '.') !== false) {
		return 'Bad string syntax to evaluate (dot char is forbidden): '.$s;
	$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "require", "include", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
		/*if (! dol_eval($extrafields->attributes[$elementtype]['enabled'][$key], 1, 1, '1')) {
					'checked'  => ((dol_eval($extrafields->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '1') <= 0) ? 0 : 1),
					'enabled'  => (abs((int) $extrafields->attributes[$extrafieldsobjectkey]['list'][$key]) != 3 && dol_eval($extrafields->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '1')),
					$value = dol_eval($extrafields->attributes[$extrafieldsobjectkey]['computed'][$key], 1, 1, '0');
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
			$visible = (int) dol_eval($val['visible'], 1, 1, '1');
				'enabled' => ($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
			$visible = (int) dol_eval($val['visible'], 1, 1, '1');
				'enabled' => ($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
		$visible = dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
		$visible = (int) dol_eval($val['visible'], 1, 1, '1');
			'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),
	'enabled'=>($visible != 3 && dol_eval($val['enabled'], 1, 1, '1')),

		$s = '(($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref: "Parent project not found"';
		$result=dol_eval($s, 1, 1, '');
		print "result = ".$result."\n";
		$this->assertEquals('Parent project not found', $result);

		$s = '(($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref: \'Parent project not found\'';
		$result=dol_eval($s, 1, 1, '');
		$result=dol_eval('$a=function() { }; $a;', 1, 1, '');

		$result=dol_eval("('ex'.'ec')('echo abc')", 1, 0);
		print "result = ".$result."\n";
		$this->assertContains('Bad string syntax to evaluate', $result);

		// Case with param onlysimplestring = 1
		$result=dol_eval('1 && $conf->abc->doesnotexist1 && $conf->def->doesnotexist1', 1, 0);	// Should return false and not a 'Bad string syntax to evaluate ...'
		print "result = ".$result."\n";
		$this->assertFalse($result);

		$result=dol_eval("(\$a.'aa')", 1, 0);
		print "result = ".$result."\n";
		$this->assertContains('Bad string syntax to evaluate', $result);