Low severityNVD Advisory· Published Dec 29, 2023· Updated Aug 2, 2024
Winter CMS Local File Inclusion through Server Side Template Injection
CVE-2023-52085
Description
Winter is a free, open-source content management system. Users with access to backend forms that include a ColorPicker FormWidget can provide a value that would then be included without further processing in the compilation of custom stylesheets via LESS. This had the potential to lead to a Local File Inclusion vulnerability. This issue has been patched in v1.2.4.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
winter/wn-backend-modulePackagist | < 1.2.4 | 1.2.4 |
Affected products
1Patches
15bc9257fe2bcAdded validation check for colourpicker form widget (#1020)
3 files changed · +167 −1
modules/backend/formwidgets/ColorPicker.php+38 −1 modified@@ -59,6 +59,16 @@ class ColorPicker extends FormWidgetBase */ public $formats = 'hex'; + /** + * @var array|string[] Patterns to validate colour string on save + */ + protected array $validationPatterns = [ + 'cmyk' => '/^cmyk\((\d{1,2}\.?\d{0,2}%,? ?){4}\)$/', + 'hex' => '/^#[\w\d]{6}$/', + 'hsl' => '/^hsla\((\d{1,3}\.?\d{0,2}%?, ?){3}\d\.?\d{0,2}?\)$/', + 'rgb' => '/^rgba\((\d{1,3}\.?\d{0,2}, ?){3}\d\.?\d{0,2}?\)$/', + ]; + // // Object properties // @@ -244,6 +254,33 @@ protected function loadAssets() */ public function getSaveValue($value) { - return strlen($value) ? $value : null; + if (!strlen($value)) { + return null; + } + + switch (is_array($this->formats) ? 'all' : $this->formats) { + case 'cmyk': + case 'hex': + case 'hsl': + case 'rgb': + if (!preg_match($this->validationPatterns[$this->formats], $value)) { + throw new ApplicationException(Lang::get('backend::lang.field.colors_invalid_input')); + } + break; + case 'all': + $valid = false; + foreach ($this->validationPatterns as $pattern) { + if (preg_match($pattern, $value)) { + $valid = true; + break; + } + } + if (!$valid) { + throw new ApplicationException(Lang::get('backend::lang.field.colors_invalid_input')); + } + break; + } + + return $value; } }
modules/backend/lang/en/lang.php+1 −0 modified@@ -11,6 +11,7 @@ 'options_method_not_exists' => "The model class :model must define a method :method() returning options for the ':field' form field.", 'options_static_method_invalid_value' => "The static method ':method()' on :class did not return a valid options array.", 'colors_method_not_exists' => "The model class :model must define a method :method() returning html color HEX codes for the ':field' form field.", + 'colors_invalid_input' => 'The color value supplied is invalid, please try again.', ], 'widget' => [ 'not_registered' => "A widget class name ':name' has not been registered",
modules/backend/tests/formwidgets/ColorPickerTest.php+128 −0 added@@ -0,0 +1,128 @@ +<?php + +namespace Backend\Tests\FormWidgets; + +use Backend\Classes\Controller; +use Backend\Classes\FormField; +use Backend\FormWidgets\ColorPicker; +use System\Tests\Bootstrap\PluginTestCase; +use Winter\Storm\Exception\ApplicationException; + +class ColorPickerTest extends PluginTestCase +{ + public function testDefaultSaveValue(): void + { + $widget = $this->makeWidget(); + + // Default only expects hex + $this->assertEquals('#3498DB', $widget->getSaveValue('#3498DB')); + + // Getting a non-hex value should throw an exception + $this->expectException(ApplicationException::class); + $widget->getSaveValue('rgba(51.9, 152, 219, 1)'); + + // Test a bunch of hex values + $this->assertEquals('#3498DB', $widget->getSaveValue('#3498DB')); + $this->assertEquals('#2980B9', $widget->getSaveValue('#2980B9')); + $this->assertEquals('#9B59B6', $widget->getSaveValue('#9B59B6')); + } + + public function testRgbSaveValue(): void + { + $widget = $this->makeWidget([ + 'formats' => 'rgb' + ]); + + // Config specifies only rgb + $this->assertEquals('rgba(51.9, 152, 219, 1)', $widget->getSaveValue('rgba(51.9, 152, 219, 1)')); + + // Getting a non-rgb value should throw an exception + $this->expectException(ApplicationException::class); + $widget->getSaveValue('#3498DB'); + + // Test a bunch of rgb values + $this->assertEquals('rgba(1, 1, 1, 1)', $widget->getSaveValue('rgba(1, 1, 1, 1)')); + $this->assertEquals('rgba(155, 89, 182, 0.5)', $widget->getSaveValue('rgba(155, 89, 182, 0.5)')); + $this->assertEquals('rgba(1, 89, 182, 0.55)', $widget->getSaveValue('rgba(1, 89, 182, 0.55)')); + } + + public function testCmykSaveValue(): void + { + $widget = $this->makeWidget([ + 'formats' => 'cmyk' + ]); + + // Config specifies only cmyk + $this->assertEquals('cmyk(76.3%, 30.6%, 0%, 14.1%)', $widget->getSaveValue('cmyk(76.3%, 30.6%, 0%, 14.1%)')); + + // Getting a non-cmyk value should throw an exception + $this->expectException(ApplicationException::class); + $widget->getSaveValue('#3498DB'); + + // Test a bunch of cmyk values + $this->assertEquals('cmyk(14.8%, 51.1%, 0%, 28.6%)', $widget->getSaveValue('cmyk(14.8%, 51.1%, 0%, 28.6%)')); + $this->assertEquals('cmyk(17%, 60.75%, 0%, 32.22%)', $widget->getSaveValue('cmyk(17%, 60.75%, 0%, 32.22%)')); + $this->assertEquals('cmyk(17.9%, 60.75%, 0%, 32.2%)', $widget->getSaveValue('cmyk(17.9%, 60.75%, 0%, 32.2%)')); + } + + public function testHslaSaveValue(): void + { + $widget = $this->makeWidget([ + 'formats' => 'hsl' + ]); + + // Config specifies only hsl + $this->assertEquals('hsla(204.1, 69.9%, 53.1%, 1)', $widget->getSaveValue('hsla(204.1, 69.9%, 53.1%, 1)')); + + // Getting a non-hsl value should throw an exception + $this->expectException(ApplicationException::class); + $widget->getSaveValue('#3498DB'); + + // Test a bunch of hsl values + $this->assertEquals('hsla(282.3, 43.6%, 47.2%, 1)', $widget->getSaveValue('hsla(282.3, 43.6%, 47.2%, 1)')); + $this->assertEquals('hsla(282.3, 43.6%, 47.2%, 0.1)', $widget->getSaveValue('hsla(282.3, 43.6%, 47.2%, 0.1)')); + $this->assertEquals('hsla(282, 43.6%, 47.2%, 0.1)', $widget->getSaveValue('hsla(282, 43.6%, 47.2%, 0.1)')); + $this->assertEquals('hsla(282, 43.56%, 47.2%, 0.1)', $widget->getSaveValue('hsla(282, 43.56%, 47.2%, 0.1)')); + $this->assertEquals('hsla(282.22, 43%, 47.2%, 0.1)', $widget->getSaveValue('hsla(282.22, 43%, 47.2%, 0.1)')); + } + + public function testAllSaveValue(): void + { + $widget = $this->makeWidget([ + 'formats' => 'all' + ]); + + // Config allows for any valid format + $this->assertEquals('#3498DB', $widget->getSaveValue('#3498DB')); + $this->assertEquals('rgba(51.9, 152, 219, 1)', $widget->getSaveValue('rgba(51.9, 152, 219, 1)')); + $this->assertEquals('cmyk(76.3%, 30.6%, 0%, 14.1%)', $widget->getSaveValue('cmyk(76.3%, 30.6%, 0%, 14.1%)')); + $this->assertEquals('hsla(204.1, 69.9%, 53.1%, 1)', $widget->getSaveValue('hsla(204.1, 69.9%, 53.1%, 1)')); + + // Getting a invalid value should throw an exception + $this->expectException(ApplicationException::class); + $widget->getSaveValue('#Winter Is Awesome'); + + $this->expectException(ApplicationException::class); + $widget->getSaveValue('rgba(51.9, 152, 219, 1) -- test'); + + $this->expectException(ApplicationException::class); + $widget->getSaveValue('Test(51.9, 152, 219, 1)'); + } + + public function testAllowCustomSaveValue(): void + { + $widget = $this->makeWidget([ + 'formats' => 'custom' + ]); + + // Config allows for any format + $this->assertEquals('rgba(51.9, 152, 219, 1)', $widget->getSaveValue('rgba(51.9, 152, 219, 1)')); + $this->assertEquals('#Winter Is Awesome', $widget->getSaveValue('#Winter Is Awesome')); + $this->assertEquals('Test(51.9, 152, 219, 1)', $widget->getSaveValue('Test(51.9, 152, 219, 1)')); + } + + protected function makeWidget(array $config = []): ColorPicker + { + return new ColorPicker(new Controller(), new FormField('test', 'Test'), $config); + } +}
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-2x7r-93ww-cxrqghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-52085ghsaADVISORY
- github.com/wintercms/winter/commit/5bc9257fe2bc47d8b786a1b1bf96bafad23d8dddghsax_refsource_MISCWEB
- github.com/wintercms/winter/security/advisories/GHSA-2x7r-93ww-cxrqghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.