From 6549932d59aef3b72a9da29294af0f30ffb77af5 Mon Sep 17 00:00:00 2001 From: Inverle Date: Mon, 7 Jul 2025 23:32:35 +0200 Subject: Disallow setting non-existent theme (#7722) Related: https://github.com/FreshRSS/xExtension-Demo/pull/2, https://github.com/FreshRSS/FreshRSS/pull/7559#issuecomment-2858083635 Mostly to make sure that no one is able to break the demo instance But the issues below could possibly be exploited in other scenarios too: * Setting a theme like `../../lib/core-extensions/UserJS`: this directory contains `metadata.json` like themes do, so FreshRSS treats it as a theme after setting it and doesn't load any CSS * Setting a theme like `x dropdown-menu`: the `dropdown-menu` class was able to get injected into the `` element since https://github.com/FreshRSS/FreshRSS/pull/7559 and turn every page blank --- app/Controllers/configureController.php | 5 ++++- app/Models/Themes.php | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 59845d710..edd04a64c 100644 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -47,7 +47,10 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController { if (Minz_Request::isPost()) { FreshRSS_Context::userConf()->language = Minz_Request::paramString('language') ?: 'en'; FreshRSS_Context::userConf()->timezone = Minz_Request::paramString('timezone'); - FreshRSS_Context::userConf()->theme = Minz_Request::paramString('theme') ?: FreshRSS_Themes::$defaultTheme; + $theme = Minz_Request::paramString('theme') ?: FreshRSS_Themes::$defaultTheme; + if (FreshRSS_Themes::exists($theme)) { + FreshRSS_Context::userConf()->theme = $theme; + } FreshRSS_Context::userConf()->darkMode = Minz_Request::paramString('darkMode') ?: 'auto'; FreshRSS_Context::userConf()->content_width = Minz_Request::paramString('content_width') ?: 'thin'; FreshRSS_Context::userConf()->topline_read = Minz_Request::paramBoolean('topline_read'); diff --git a/app/Models/Themes.php b/app/Models/Themes.php index ef44b0b75..bc220aa50 100644 --- a/app/Models/Themes.php +++ b/app/Models/Themes.php @@ -15,6 +15,12 @@ class FreshRSS_Themes extends Minz_Model { )); } + public static function exists(string $theme_id): bool { + $theme_dir = PUBLIC_PATH . self::$themesUrl . $theme_id; + return str_replace(['..', '/', DIRECTORY_SEPARATOR], '', $theme_id) === $theme_id + && file_exists($theme_dir . '/metadata.json'); + } + /** @return array,theme-color?:string|array{dark?:string,light?:string,default?:string}}> */ public static function get(): array { $themes_list = self::getList(); -- cgit v1.2.3