VYPR
Moderate severityNVD Advisory· Published Jul 25, 2023· Updated Feb 13, 2025

Contao cross site scripting vulnerability via input unit widget

CVE-2023-36806

Description

Contao is an open source content management system. Starting in version 4.0.0 and prior to versions 4.9.42, 4.13.28, and 5.1.10, it is possible for untrusted backend users to inject malicious code into headline fields in the back end, which will be executed both in the element preview (back end) and on the website (front end). Installations are only affected if there are untrusted back end users who have the rights to modify headline fields, or other fields using the input unit widget. Contao 4.9.42, 4.13.28, and 5.1.10 have a patch for this issue. As a workaround, disable the login for all untrusted back end users.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Contao CMS versions before 4.9.42, 4.13.28, and 5.1.10 allow stored XSS via untrusted backend users injecting malicious code into headline fields.

Vulnerability

Type CVE-2023-36806 is a stored cross-site scripting (XSS) vulnerability in the Contao content management system. The root cause is the lack of validation for unit options in the InputUnit and TimePeriod widgets, allowing untrusted backend users to inject arbitrary JavaScript code into headline fields [1].

Exploitation

An attacker must have a backend user account with the rights to modify headline fields or other fields using the input unit widget. By crafting a malicious unit value, the injected code is stored and executed when the element is previewed in the back end or rendered on the website [1]. No additional privileges are required beyond those for editing content.

Impact

Successful exploitation leads to persistent execution of malicious scripts in the context of the victim's browser, potentially enabling theft of session cookies, defacement, or other client-side attacks. The vulnerability affects both the administrative interface and the public-facing website.

Mitigation

The issue is patched in Contao versions 4.9.42, 4.13.28, and 5.1.10 [2][3][4]. As a workaround, administrators can disable login for all untrusted back end users to prevent exploitation [1].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
contao/core-bundlePackagist
>= 4.0.0, < 4.9.424.9.42
contao/core-bundlePackagist
>= 4.10.0, < 4.13.284.13.28
contao/core-bundlePackagist
>= 5.0.0, < 5.1.105.1.10

Affected products

2

Patches

3
ccb64c777eb0

Merge pull request from GHSA-4gpr-p634-922x

https://github.com/contao/contaoMartin AuswögerJul 25, 2023via ghsa
3 files changed · +35 35
  • core-bundle/src/Resources/contao/widgets/InputUnit.php+11 11 modified
    @@ -32,12 +32,6 @@ class InputUnit extends Widget
     	 */
     	protected $strTemplate = 'be_widget';
     
    -	/**
    -	 * Units
    -	 * @var array
    -	 */
    -	protected $arrUnits = array();
    -
     	/**
     	 * Add specific attributes
     	 *
    @@ -72,7 +66,7 @@ public function __set($strKey, $varValue)
     				break;
     
     			case 'options':
    -				$this->arrUnits = StringUtil::deserialize($varValue);
    +				$this->arrOptions = StringUtil::deserialize($varValue);
     				break;
     
     			default:
    @@ -82,8 +76,6 @@ public function __set($strKey, $varValue)
     	}
     
     	/**
    -	 * Do not validate unit fields
    -	 *
     	 * @param mixed $varInput
     	 *
     	 * @return mixed
    @@ -92,7 +84,15 @@ protected function validator($varInput)
     	{
     		foreach ($varInput as $k=>$v)
     		{
    -			if ($k != 'unit')
    +			if ($k == 'unit')
    +			{
    +				if (!$this->isValidOption($v))
    +				{
    +					$varInput[$k] = '';
    +					$this->addError($GLOBALS['TL_LANG']['ERR']['invalid']);
    +				}
    +			}
    +			else
     			{
     				$varInput[$k] = parent::validator($v);
     			}
    @@ -132,7 +132,7 @@ public function generate()
     	{
     		$arrUnits = array();
     
    -		foreach ($this->arrUnits as $arrUnit)
    +		foreach ($this->arrOptions as $arrUnit)
     		{
     			$arrUnits[] = sprintf(
     				'<option value="%s"%s>%s</option>',
    
  • core-bundle/src/Resources/contao/widgets/TimePeriod.php+13 13 modified
    @@ -31,12 +31,6 @@ class TimePeriod extends Widget
     	 */
     	protected $strTemplate = 'be_widget';
     
    -	/**
    -	 * Units
    -	 * @var array
    -	 */
    -	protected $arrUnits = array();
    -
     	/**
     	 * Add specific attributes
     	 *
    @@ -67,7 +61,7 @@ public function __set($strKey, $varValue)
     				break;
     
     			case 'options':
    -				$this->arrUnits = StringUtil::deserialize($varValue);
    +				$this->arrOptions = StringUtil::deserialize($varValue);
     				break;
     
     			default:
    @@ -77,8 +71,6 @@ public function __set($strKey, $varValue)
     	}
     
     	/**
    -	 * Do not validate unit fields
    -	 *
     	 * @param mixed $varInput
     	 *
     	 * @return mixed
    @@ -87,7 +79,15 @@ protected function validator($varInput)
     	{
     		foreach ($varInput as $k=>$v)
     		{
    -			if ($k != 'unit')
    +			if ($k == 'unit')
    +			{
    +				if (!$this->isValidOption($v))
    +				{
    +					$varInput[$k] = '';
    +					$this->addError($GLOBALS['TL_LANG']['ERR']['invalid']);
    +				}
    +			}
    +			else
     			{
     				$varInput[$k] = parent::validator($v);
     			}
    @@ -128,12 +128,12 @@ public function generate()
     		$arrUnits = array();
     
     		// Add an empty option if there are none (see #5067)
    -		if (empty($this->arrUnits))
    +		if (empty($this->arrOptions))
     		{
    -			$this->arrUnits = array(array('value'=>'', 'label'=>'-'));
    +			$this->arrOptions = array(array('value'=>'', 'label'=>'-'));
     		}
     
    -		foreach ($this->arrUnits as $arrUnit)
    +		foreach ($this->arrOptions as $arrUnit)
     		{
     			$arrUnits[] = sprintf(
     				'<option value="%s"%s>%s</option>',
    
  • core-bundle/src/Resources/contao/widgets/TrblField.php+11 11 modified
    @@ -30,12 +30,6 @@ class TrblField extends Widget
     	 */
     	protected $strTemplate = 'be_widget';
     
    -	/**
    -	 * Units
    -	 * @var array
    -	 */
    -	protected $arrUnits = array();
    -
     	/**
     	 * Add specific attributes
     	 *
    @@ -54,7 +48,7 @@ public function __set($strKey, $varValue)
     				break;
     
     			case 'options':
    -				$this->arrUnits = StringUtil::deserialize($varValue);
    +				$this->arrOptions = StringUtil::deserialize($varValue);
     				break;
     
     			default:
    @@ -64,8 +58,6 @@ public function __set($strKey, $varValue)
     	}
     
     	/**
    -	 * Do not validate unit fields
    -	 *
     	 * @param mixed $varInput
     	 *
     	 * @return mixed
    @@ -74,7 +66,15 @@ protected function validator($varInput)
     	{
     		foreach ($varInput as $k=>$v)
     		{
    -			if ($k != 'unit')
    +			if ($k == 'unit')
    +			{
    +				if (!$this->isValidOption($v))
    +				{
    +					$varInput[$k] = '';
    +					$this->addError($GLOBALS['TL_LANG']['ERR']['invalid']);
    +				}
    +			}
    +			else
     			{
     				$varInput[$k] = parent::validator($v);
     			}
    @@ -114,7 +114,7 @@ public function generate()
     	{
     		$arrUnits = array();
     
    -		foreach ($this->arrUnits as $arrUnit)
    +		foreach ($this->arrOptions as $arrUnit)
     		{
     			$arrUnits[] = sprintf(
     				'<option value="%s"%s>%s</option>',
    
5c9aff32cfc1

Merge pull request from GHSA-4gpr-p634-922x

https://github.com/contao/contaoMartin AuswögerJul 25, 2023via ghsa
3 files changed · +35 35
  • core-bundle/src/Resources/contao/widgets/InputUnit.php+11 11 modified
    @@ -34,12 +34,6 @@ class InputUnit extends Widget
     	 */
     	protected $strTemplate = 'be_widget';
     
    -	/**
    -	 * Units
    -	 * @var array
    -	 */
    -	protected $arrUnits = array();
    -
     	/**
     	 * Add specific attributes
     	 *
    @@ -74,7 +68,7 @@ public function __set($strKey, $varValue)
     				break;
     
     			case 'options':
    -				$this->arrUnits = StringUtil::deserialize($varValue);
    +				$this->arrOptions = StringUtil::deserialize($varValue);
     				break;
     
     			default:
    @@ -84,8 +78,6 @@ public function __set($strKey, $varValue)
     	}
     
     	/**
    -	 * Do not validate unit fields
    -	 *
     	 * @param mixed $varInput
     	 *
     	 * @return mixed
    @@ -94,7 +86,15 @@ protected function validator($varInput)
     	{
     		foreach ($varInput as $k=>$v)
     		{
    -			if ($k != 'unit')
    +			if ($k == 'unit')
    +			{
    +				if (!$this->isValidOption($v))
    +				{
    +					$varInput[$k] = '';
    +					$this->addError($GLOBALS['TL_LANG']['ERR']['invalid']);
    +				}
    +			}
    +			else
     			{
     				$varInput[$k] = parent::validator($v);
     			}
    @@ -134,7 +134,7 @@ public function generate()
     	{
     		$arrUnits = array();
     
    -		foreach ($this->arrUnits as $arrUnit)
    +		foreach ($this->arrOptions as $arrUnit)
     		{
     			$arrUnits[] = sprintf(
     				'<option value="%s"%s>%s</option>',
    
  • core-bundle/src/Resources/contao/widgets/TimePeriod.php+13 13 modified
    @@ -33,12 +33,6 @@ class TimePeriod extends Widget
     	 */
     	protected $strTemplate = 'be_widget';
     
    -	/**
    -	 * Units
    -	 * @var array
    -	 */
    -	protected $arrUnits = array();
    -
     	/**
     	 * Add specific attributes
     	 *
    @@ -69,7 +63,7 @@ public function __set($strKey, $varValue)
     				break;
     
     			case 'options':
    -				$this->arrUnits = StringUtil::deserialize($varValue);
    +				$this->arrOptions = StringUtil::deserialize($varValue);
     				break;
     
     			default:
    @@ -79,8 +73,6 @@ public function __set($strKey, $varValue)
     	}
     
     	/**
    -	 * Do not validate unit fields
    -	 *
     	 * @param mixed $varInput
     	 *
     	 * @return mixed
    @@ -89,7 +81,15 @@ protected function validator($varInput)
     	{
     		foreach ($varInput as $k=>$v)
     		{
    -			if ($k != 'unit')
    +			if ($k == 'unit')
    +			{
    +				if (!$this->isValidOption($v))
    +				{
    +					$varInput[$k] = '';
    +					$this->addError($GLOBALS['TL_LANG']['ERR']['invalid']);
    +				}
    +			}
    +			else
     			{
     				$varInput[$k] = parent::validator($v);
     			}
    @@ -130,12 +130,12 @@ public function generate()
     		$arrUnits = array();
     
     		// Add an empty option if there are none (see #5067)
    -		if (empty($this->arrUnits))
    +		if (empty($this->arrOptions))
     		{
    -			$this->arrUnits = array(array('value'=>'', 'label'=>'-'));
    +			$this->arrOptions = array(array('value'=>'', 'label'=>'-'));
     		}
     
    -		foreach ($this->arrUnits as $arrUnit)
    +		foreach ($this->arrOptions as $arrUnit)
     		{
     			$arrUnits[] = sprintf(
     				'<option value="%s"%s>%s</option>',
    
  • core-bundle/src/Resources/contao/widgets/TrblField.php+11 11 modified
    @@ -32,12 +32,6 @@ class TrblField extends Widget
     	 */
     	protected $strTemplate = 'be_widget';
     
    -	/**
    -	 * Units
    -	 * @var array
    -	 */
    -	protected $arrUnits = array();
    -
     	/**
     	 * Add specific attributes
     	 *
    @@ -56,7 +50,7 @@ public function __set($strKey, $varValue)
     				break;
     
     			case 'options':
    -				$this->arrUnits = StringUtil::deserialize($varValue);
    +				$this->arrOptions = StringUtil::deserialize($varValue);
     				break;
     
     			default:
    @@ -66,8 +60,6 @@ public function __set($strKey, $varValue)
     	}
     
     	/**
    -	 * Do not validate unit fields
    -	 *
     	 * @param mixed $varInput
     	 *
     	 * @return mixed
    @@ -76,7 +68,15 @@ protected function validator($varInput)
     	{
     		foreach ($varInput as $k=>$v)
     		{
    -			if ($k != 'unit')
    +			if ($k == 'unit')
    +			{
    +				if (!$this->isValidOption($v))
    +				{
    +					$varInput[$k] = '';
    +					$this->addError($GLOBALS['TL_LANG']['ERR']['invalid']);
    +				}
    +			}
    +			else
     			{
     				$varInput[$k] = parent::validator($v);
     			}
    @@ -116,7 +116,7 @@ public function generate()
     	{
     		$arrUnits = array();
     
    -		foreach ($this->arrUnits as $arrUnit)
    +		foreach ($this->arrOptions as $arrUnit)
     		{
     			$arrUnits[] = sprintf(
     				'<option value="%s"%s>%s</option>',
    
c98585d36baa

Merge pull request from GHSA-4gpr-p634-922x

https://github.com/contao/contaoMartin AuswögerJul 25, 2023via ghsa
3 files changed · +35 35
  • core-bundle/contao/widgets/InputUnit.php+11 11 modified
    @@ -32,12 +32,6 @@ class InputUnit extends Widget
     	 */
     	protected $strTemplate = 'be_widget';
     
    -	/**
    -	 * Units
    -	 * @var array
    -	 */
    -	protected $arrUnits = array();
    -
     	/**
     	 * Add specific attributes
     	 *
    @@ -72,7 +66,7 @@ public function __set($strKey, $varValue)
     				break;
     
     			case 'options':
    -				$this->arrUnits = StringUtil::deserialize($varValue);
    +				$this->arrOptions = StringUtil::deserialize($varValue);
     				break;
     
     			default:
    @@ -82,8 +76,6 @@ public function __set($strKey, $varValue)
     	}
     
     	/**
    -	 * Do not validate unit fields
    -	 *
     	 * @param mixed $varInput
     	 *
     	 * @return mixed
    @@ -92,7 +84,15 @@ protected function validator($varInput)
     	{
     		foreach ($varInput as $k=>$v)
     		{
    -			if ($k != 'unit')
    +			if ($k == 'unit')
    +			{
    +				if (!$this->isValidOption($v))
    +				{
    +					$varInput[$k] = '';
    +					$this->addError($GLOBALS['TL_LANG']['ERR']['invalid']);
    +				}
    +			}
    +			else
     			{
     				$varInput[$k] = parent::validator($v);
     			}
    @@ -132,7 +132,7 @@ public function generate()
     	{
     		$arrUnits = array();
     
    -		foreach ($this->arrUnits as $arrUnit)
    +		foreach ($this->arrOptions as $arrUnit)
     		{
     			$arrUnits[] = sprintf(
     				'<option value="%s"%s>%s</option>',
    
  • core-bundle/contao/widgets/TimePeriod.php+13 13 modified
    @@ -31,12 +31,6 @@ class TimePeriod extends Widget
     	 */
     	protected $strTemplate = 'be_widget';
     
    -	/**
    -	 * Units
    -	 * @var array
    -	 */
    -	protected $arrUnits = array();
    -
     	/**
     	 * Add specific attributes
     	 *
    @@ -67,7 +61,7 @@ public function __set($strKey, $varValue)
     				break;
     
     			case 'options':
    -				$this->arrUnits = StringUtil::deserialize($varValue);
    +				$this->arrOptions = StringUtil::deserialize($varValue);
     				break;
     
     			default:
    @@ -77,8 +71,6 @@ public function __set($strKey, $varValue)
     	}
     
     	/**
    -	 * Do not validate unit fields
    -	 *
     	 * @param mixed $varInput
     	 *
     	 * @return mixed
    @@ -87,7 +79,15 @@ protected function validator($varInput)
     	{
     		foreach ($varInput as $k=>$v)
     		{
    -			if ($k != 'unit')
    +			if ($k == 'unit')
    +			{
    +				if (!$this->isValidOption($v))
    +				{
    +					$varInput[$k] = '';
    +					$this->addError($GLOBALS['TL_LANG']['ERR']['invalid']);
    +				}
    +			}
    +			else
     			{
     				$varInput[$k] = parent::validator($v);
     			}
    @@ -128,12 +128,12 @@ public function generate()
     		$arrUnits = array();
     
     		// Add an empty option if there are none (see #5067)
    -		if (empty($this->arrUnits))
    +		if (empty($this->arrOptions))
     		{
    -			$this->arrUnits = array(array('value'=>'', 'label'=>'-'));
    +			$this->arrOptions = array(array('value'=>'', 'label'=>'-'));
     		}
     
    -		foreach ($this->arrUnits as $arrUnit)
    +		foreach ($this->arrOptions as $arrUnit)
     		{
     			$arrUnits[] = sprintf(
     				'<option value="%s"%s>%s</option>',
    
  • core-bundle/contao/widgets/TrblField.php+11 11 modified
    @@ -30,12 +30,6 @@ class TrblField extends Widget
     	 */
     	protected $strTemplate = 'be_widget';
     
    -	/**
    -	 * Units
    -	 * @var array
    -	 */
    -	protected $arrUnits = array();
    -
     	/**
     	 * Add specific attributes
     	 *
    @@ -54,7 +48,7 @@ public function __set($strKey, $varValue)
     				break;
     
     			case 'options':
    -				$this->arrUnits = StringUtil::deserialize($varValue);
    +				$this->arrOptions = StringUtil::deserialize($varValue);
     				break;
     
     			default:
    @@ -64,8 +58,6 @@ public function __set($strKey, $varValue)
     	}
     
     	/**
    -	 * Do not validate unit fields
    -	 *
     	 * @param mixed $varInput
     	 *
     	 * @return mixed
    @@ -74,7 +66,15 @@ protected function validator($varInput)
     	{
     		foreach ($varInput as $k=>$v)
     		{
    -			if ($k != 'unit')
    +			if ($k == 'unit')
    +			{
    +				if (!$this->isValidOption($v))
    +				{
    +					$varInput[$k] = '';
    +					$this->addError($GLOBALS['TL_LANG']['ERR']['invalid']);
    +				}
    +			}
    +			else
     			{
     				$varInput[$k] = parent::validator($v);
     			}
    @@ -114,7 +114,7 @@ public function generate()
     	{
     		$arrUnits = array();
     
    -		foreach ($this->arrUnits as $arrUnit)
    +		foreach ($this->arrOptions as $arrUnit)
     		{
     			$arrUnits[] = sprintf(
     				'<option value="%s"%s>%s</option>',
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

8

News mentions

0

No linked articles in our index yet.