From 929185cf6723864f8962ce6d6c56c255e5ea2fc6 Mon Sep 17 00:00:00 2001 From: Gregor Harlan Date: Sat, 30 May 2026 11:42:09 +0200 Subject: [PATCH 1/2] fix(mediapool): block dangerous extensions in any filename segment isAllowedExtension only rejected a blocked extension when it was the terminal extension or the segment directly before it (*.php.). Filenames with a blocked extension as a non-terminal segment in a chain of three or more, e.g. shell.php.any.jpg, slipped through and could be executed as PHP on web servers that map handlers via a multi-extension match (mod_mime AddHandler / non-anchored FilesMatch). Check each dot-separated segment against the blocked list instead. This matches whole segments, so it still allows foo.json and js_datei.txt (no false positive), while also fixing a case-sensitivity gap in the previous str_ends_with check (it ran against the raw filename). Regression introduced in 9d008697d (#6213). --- redaxo/src/addons/mediapool/lib/mediapool.php | 12 ++++++------ redaxo/src/addons/mediapool/tests/mediapool_test.php | 6 ++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/redaxo/src/addons/mediapool/lib/mediapool.php b/redaxo/src/addons/mediapool/lib/mediapool.php index 72ea1d44c0..53783664d1 100644 --- a/redaxo/src/addons/mediapool/lib/mediapool.php +++ b/redaxo/src/addons/mediapool/lib/mediapool.php @@ -114,13 +114,13 @@ public static function isAllowedExtension(string $filename, array $args = []): b return false; } + // A blocked extension must not appear as a dot-separated segment anywhere in the filename, + // to prevent double/multi extension vulnerabilities: some webspaces execute a file named + // e.g. `foo.php.txt` or `foo.php.any.jpg` as php. Matching whole segments (instead of a + // substring) avoids false positives like `foo.json` (contains `.js`) or `js_datei.txt`. $blockedExtensions = self::getBlockedExtensions(); - foreach ($blockedExtensions as $blockedExtension) { - // $blockedExtensions extensions are not allowed within filenames, to prevent double extension vulnerabilities: - // -> some webspaces execute files named file.php.txt as php - if (str_ends_with($filename, '.' . $blockedExtension) // Prüfe ob der String mit der verbotenen Endung endet - || str_ends_with($filename, '.' . $blockedExtension . '.' . $fileExt) // prüfe ob es keine doppelte Endung der Form *.php.ext gibt - ) { + foreach (explode('.', mb_strtolower($filename)) as $segment) { + if (in_array($segment, $blockedExtensions, true)) { return false; } } diff --git a/redaxo/src/addons/mediapool/tests/mediapool_test.php b/redaxo/src/addons/mediapool/tests/mediapool_test.php index 03b84dee10..80e502c530 100644 --- a/redaxo/src/addons/mediapool/tests/mediapool_test.php +++ b/redaxo/src/addons/mediapool/tests/mediapool_test.php @@ -24,9 +24,15 @@ public static function provideIsAllowedExtension(): array [false, '.htaccess'], [false, '.htpasswd'], [false, 'foo.js.txt'], + [false, 'foo.js.any.txt'], + [false, 'shell.php.any.jpg'], + [false, 'shell.PHP.any.JPG'], + [false, 'shell.phtml.any.jpg'], [true, 'js_datei.txt'], [true, 'foo.json'], + [true, 'foo.any.json'], [true, 'php_logo.jpg'], + [true, 'php_logo.any.jpg'], [true, 'foo.bar.png', ['types' => 'jpg,png,gif']], [false, 'foo.bar.txt', ['types' => 'jpg,png,gif']], [false, 'foo.bar.php', ['types' => 'jpg,png,gif,php']], From f579a8f612e0befb41300b73cc847f6d53987e72 Mon Sep 17 00:00:00 2001 From: gharlan <330436+gharlan@users.noreply.github.com> Date: Mon, 1 Jun 2026 09:59:49 +0000 Subject: [PATCH 2/2] chore: update psalm baseline --- .tools/psalm/baseline.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.tools/psalm/baseline.xml b/.tools/psalm/baseline.xml index 794d0e6271..528a89beb3 100644 --- a/.tools/psalm/baseline.xml +++ b/.tools/psalm/baseline.xml @@ -1256,13 +1256,6 @@ - - - - - - - getProperty('allowed_mime_types', [])]]> getProperty('blocked_extensions')]]>