Skip to content

Commit 2d90a1f

Browse files
authored
Merge commit from fork
CVE-2023-27577 restricted @import and data-uri() in the custom_less setting, but the same restriction was never applied to other settings registered as LESS config variables (e.g. theme_primary_color). Those values are interpolated verbatim into the LESS source, allowing an admin-level attacker to read local files or trigger SSRF via the LESS @import directive. Apply the same check to every dirty setting whose key is registered via flarum.less.config (built-in theme colors and Extend\Settings::registerLessConfigVar()).
1 parent 5e429dd commit 2d90a1f

2 files changed

Lines changed: 72 additions & 6 deletions

File tree

framework/core/src/Forum/ValidateCustomLess.php

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,26 @@ public function whenSettingsSaving(Saving $event): void
4343
return;
4444
}
4545

46-
// Restrict what features can be used in custom LESS
47-
if (isset($event->settings['custom_less']) && preg_match('/@import|data-uri\s*\(/i', $event->settings['custom_less'])) {
48-
$translator = $this->container->make(TranslatorInterface::class);
46+
// Restrict what features can be used in custom LESS. This applies to
47+
// the `custom_less` setting as well as any setting registered as a
48+
// LESS config variable (e.g. `theme_primary_color`), since those
49+
// values are interpolated directly into the LESS source.
50+
$lessFeatureKeys = array_merge(
51+
isset($event->settings['custom_less']) ? ['custom_less'] : [],
52+
array_intersect(
53+
array_keys($event->settings),
54+
array_column($this->customLessSettings, 'key')
55+
)
56+
);
57+
58+
foreach ($lessFeatureKeys as $key) {
59+
if (is_string($event->settings[$key]) && preg_match('/@import|data-uri\s*\(/i', $event->settings[$key])) {
60+
$translator = $this->container->make(TranslatorInterface::class);
4961

50-
throw new ValidationException([
51-
'custom_less' => $translator->trans('core.admin.appearance.custom_styles_cannot_use_less_features')
52-
]);
62+
throw new ValidationException([
63+
$key => $translator->trans('core.admin.appearance.custom_styles_cannot_use_less_features')
64+
]);
65+
}
5366
}
5467

5568
// We haven't saved the settings yet, but we want to trial a full

framework/core/tests/integration/api/settings/SetTest.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,57 @@ public function max_setting_length_validated()
7878

7979
$this->assertEquals(422, $response->getStatusCode());
8080
}
81+
82+
#[Test]
83+
public function theme_primary_color_rejects_less_import()
84+
{
85+
$response = $this->send(
86+
$this->request('POST', '/api/settings', [
87+
'authenticatedAs' => 1,
88+
'json' => [
89+
'theme_primary_color' => "#4D698E;@import (inline) '/etc/passwd';",
90+
],
91+
])
92+
);
93+
94+
$this->assertEquals(422, $response->getStatusCode());
95+
$this->assertNotEquals(
96+
"#4D698E;@import (inline) '/etc/passwd';",
97+
$this->app->getContainer()->make('flarum.settings')->get('theme_primary_color')
98+
);
99+
}
100+
101+
#[Test]
102+
public function theme_secondary_color_rejects_less_import()
103+
{
104+
$response = $this->send(
105+
$this->request('POST', '/api/settings', [
106+
'authenticatedAs' => 1,
107+
'json' => [
108+
'theme_secondary_color' => "#4D698E;@import (inline) '/etc/passwd';",
109+
],
110+
])
111+
);
112+
113+
$this->assertEquals(422, $response->getStatusCode());
114+
$this->assertNotEquals(
115+
"#4D698E;@import (inline) '/etc/passwd';",
116+
$this->app->getContainer()->make('flarum.settings')->get('theme_secondary_color')
117+
);
118+
}
119+
120+
#[Test]
121+
public function theme_primary_color_rejects_data_uri()
122+
{
123+
$response = $this->send(
124+
$this->request('POST', '/api/settings', [
125+
'authenticatedAs' => 1,
126+
'json' => [
127+
'theme_primary_color' => "#4D698E;background:data-uri('/etc/passwd');",
128+
],
129+
])
130+
);
131+
132+
$this->assertEquals(422, $response->getStatusCode());
133+
}
81134
}

0 commit comments

Comments
 (0)