Skip to content

Commit 3ffc083

Browse files
bnfohader
authored andcommitted
[SECURITY] Fix open redirection in GeneralUtility::sanitizeLocalUrl
Resolves: #109694 Releases: main, 14.3, 13.4 Change-Id: I8c8ce23c3d6042e5d1afffa6e35237e6a746fd08 Security-Bulletin: TYPO3-CORE-SA-2026-009 Security-References: CVE-2026-47347 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/94404 Reviewed-by: Oliver Hader <oliver.hader@typo3.org> Tested-by: Oliver Hader <oliver.hader@typo3.org>
1 parent 2030617 commit 3ffc083

2 files changed

Lines changed: 60 additions & 8 deletions

File tree

typo3/sysext/core/Classes/Utility/GeneralUtility.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2127,8 +2127,28 @@ public static function sanitizeLocalUrl(string $url, ServerRequestInterface $req
21272127
{
21282128
$sanitizedUrl = '';
21292129
if (!empty($url)) {
2130-
if (strpbrk($url, "\n\r\x00") !== false) {
2131-
static::getLogger()->notice('URL "{url}" contains unexpected whitespace and was denied as local url.', ['url' => $url]);
2130+
$validUrlCharacters = [
2131+
// Percent-Encoding: https://datatracker.ietf.org/doc/html/rfc3986#section-2.1
2132+
'%',
2133+
2134+
// Reserved Characters: https://datatracker.ietf.org/doc/html/rfc3986#section-2.2
2135+
// gen-delims
2136+
':', '/', '?', '#', '[', ']', '@',
2137+
// sub-delims
2138+
'!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=',
2139+
2140+
// Unreserved Characters: https://datatracker.ietf.org/doc/html/rfc3986#section-2.3
2141+
'-', '.', '_', '~',
2142+
// ALPHA
2143+
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
2144+
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
2145+
// DIGIT
2146+
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
2147+
];
2148+
2149+
$hasInvalidCharacters = str_replace($validUrlCharacters, '', $url) !== '';
2150+
if ($hasInvalidCharacters) {
2151+
static::getLogger()->notice('The URL "{url}" contains unexpected characters and was denied as local url.', ['url' => $url]);
21322152
return '';
21332153
}
21342154

typo3/sysext/core/Tests/Unit/Utility/GeneralUtilityTest.php

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,18 +1365,28 @@ public static function sanitizeLocalUrlValidUrlsDataProvider(): array
13651365
'localhost',
13661366
'/cms/',
13671367
],
1368-
'/cms/typo3/alt_intro.php&param=oneparam' => [
1369-
'/cms/typo3/alt_intro.php&param=oneparam',
1368+
'/cms/foo/%3Fbar?baz' => [
1369+
'/cms/foo/%3Fbar?baz',
13701370
'localhost',
13711371
'/cms/',
13721372
],
1373-
'/cms/typo3/alt_intro.php&param=oneparam with spaces' => [
1374-
'/cms/typo3/alt_intro.php&param=oneparam with spaces',
1373+
'/cms/typo3/alt_intro.php?param=oneparam' => [
1374+
'/cms/typo3/alt_intro.php?param=oneparam',
13751375
'localhost',
13761376
'/cms/',
13771377
],
1378-
'/cms/typo3/alt_intro.php&param=oneparam with spaces&normalparam=2' => [
1379-
'/cms/typo3/alt_intro.php&param=oneparam with spaces',
1378+
'/cms/typo3/alt_intro.php?param=oneparam+with+spaces' => [
1379+
'/cms/typo3/alt_intro.php?param=oneparam+with+spaces',
1380+
'localhost',
1381+
'/cms/',
1382+
],
1383+
'/cms/typo3/alt_intro.php?param=oneparam%20with%20spaces' => [
1384+
'/cms/typo3/alt_intro.php?param=oneparam%20with%20spaces',
1385+
'localhost',
1386+
'/cms/',
1387+
],
1388+
'/cms/typo3/alt_intro.php?param=oneparam%20with%20spaces&normalparam=2' => [
1389+
'/cms/typo3/alt_intro.php?param=oneparam%20with%20spaces',
13801390
'localhost',
13811391
'/cms/',
13821392
],
@@ -1440,7 +1450,28 @@ public static function sanitizeLocalUrlInvalidDataProvider(): array
14401450
'empty string' => [''],
14411451
'http domain' => ['http://www.google.de/'],
14421452
'https domain' => ['https://www.google.de/'],
1453+
'https domain with' => ['https://www.google.de/'],
1454+
'https domain with escape at start' => ['https:\\//www.google.de'],
1455+
'https domain with escape in between' => ['https:/\\/www.google.de'],
1456+
'https domain with escape after' => ['https://\\www.google.de'],
1457+
'https domain with escape instead of slash' => ['https:/\\www.google.de'],
1458+
'https domain with double backslash' => ['https:\\\\www.google.de'],
1459+
'https domain with double backslash and one slash' => ['https:\\/www.google.de'],
1460+
'https domain with quad slash' => ['https:////www.google.de'],
1461+
'https domain with newline' => ["htt\nps://www.google.de"],
14431462
'domain without schema' => ['//www.google.de/'],
1463+
'domain without schema escape at start' => ['\\//www.google.de', true],
1464+
'domain without schema escape in between' => ['/\\/www.google.de', true],
1465+
'domain without schema escape after' => ['//\\www.google.de', true],
1466+
'domain without schema escape instead of slash' => ['/\\www.google.de', true],
1467+
'domain without schema with double backslash' => ['\\\\www.google.de', true],
1468+
'domain without schema with double backslash and one slash' => ['\\/www.google.de', true],
1469+
'domain without schema with quad slash' => ['////www.google.de'],
1470+
'domain without schema with newline' => ["/\n/www.google.de", true],
1471+
'domain without schema with EOT' => ["\x04//google.de", true],
1472+
'domain without schema with bell' => ["\x07//google.de", true],
1473+
'domain without schema with backspace' => ["\x08//google.de", true],
1474+
'domain without schema with form feed' => ["\x0c//google.de", true],
14441475
'XSS attempt' => ['" onmouseover="alert(123)"'],
14451476
'invalid URL, UNC path' => ['\\\\foo\\bar\\'],
14461477
'invalid URL, HTML break out attempt' => ['" >blabuubb'],
@@ -1450,6 +1481,7 @@ public static function sanitizeLocalUrlInvalidDataProvider(): array
14501481
'relative URL with location header injection attempt (not known to work) via vertical white space' => ["\v" . '//evil.site/'],
14511482
'HTTP header smuggling attempt' => ["/\r\nX-Injected: evil", true],
14521483
'null-byte break out attempt' => ["http\x00://www.google.de"],
1484+
'path invalid because it contains unencoded spaces' => ['/cms/typo3/alt_intro.php&param=oneparam with spaces', true],
14531485
];
14541486
}
14551487

0 commit comments

Comments
 (0)