Contao cross site scripting vulnerability via input unit widget
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.
| Package | Affected versions | Patched versions |
|---|---|---|
contao/core-bundlePackagist | >= 4.0.0, < 4.9.42 | 4.9.42 |
contao/core-bundlePackagist | >= 4.10.0, < 4.13.28 | 4.13.28 |
contao/core-bundlePackagist | >= 5.0.0, < 5.1.10 | 5.1.10 |
Affected products
2- contao/contaov5Range: >= 4.0.0, < 4.9.42
Patches
3ccb64c777eb0Merge pull request from GHSA-4gpr-p634-922x
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>',
5c9aff32cfc1Merge pull request from GHSA-4gpr-p634-922x
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>',
c98585d36baaMerge pull request from GHSA-4gpr-p634-922x
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- github.com/advisories/GHSA-4gpr-p634-922xghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-36806ghsaADVISORY
- github.com/contao/contao/commit/5c9aff32cfc1f7dc452a045862ac2f86a6b9b4b4ghsax_refsource_MISCWEB
- github.com/contao/contao/commit/c98585d36baa25fda69c062421e7e7eadc53c82bghsax_refsource_MISCWEB
- github.com/contao/contao/commit/ccb64c777eb0f9c0e6490c9135d80e915d37cd32ghsax_refsource_MISCWEB
- github.com/contao/contao/security/advisories/GHSA-4gpr-p634-922xghsax_refsource_CONFIRMWEB
- herolab.usd.de/security-advisories/usd-2023-0020ghsaWEB
- herolab.usd.de/security-advisories/usd-2023-0020/mitre
News mentions
0No linked articles in our index yet.