Skip to content

Commit 22c2dd5

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/+/94402 Tested-by: Oliver Hader <oliver.hader@typo3.org> Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
1 parent eb2b225 commit 22c2dd5

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
@@ -2595,8 +2595,28 @@ public static function sanitizeLocalUrl(string $url): string
25952595
{
25962596
$sanitizedUrl = '';
25972597
if (!empty($url)) {
2598-
if (strpbrk($url, "\n\r\x00") !== false) {
2599-
static::getLogger()->notice('URL "{url}" contains unexpected whitespace and was denied as local url.', ['url' => $url]);
2598+
$validUrlCharacters = [
2599+
// Percent-Encoding: https://datatracker.ietf.org/doc/html/rfc3986#section-2.1
2600+
'%',
2601+
2602+
// Reserved Characters: https://datatracker.ietf.org/doc/html/rfc3986#section-2.2
2603+
// gen-delims
2604+
':', '/', '?', '#', '[', ']', '@',
2605+
// sub-delims
2606+
'!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=',
2607+
2608+
// Unreserved Characters: https://datatracker.ietf.org/doc/html/rfc3986#section-2.3
2609+
'-', '.', '_', '~',
2610+
// ALPHA
2611+
'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',
2612+
'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',
2613+
// DIGIT
2614+
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
2615+
];
2616+
2617+
$hasInvalidCharacters = str_replace($validUrlCharacters, '', $url) !== '';
2618+
if ($hasInvalidCharacters) {
2619+
static::getLogger()->notice('The URL "{url}" contains unexpected characters and was denied as local url.', ['url' => $url]);
26002620
return '';
26012621
}
26022622

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

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,18 +1384,28 @@ public static function sanitizeLocalUrlValidUrlsDataProvider(): array
13841384
'localhost',
13851385
'/cms/',
13861386
],
1387-
'/cms/typo3/alt_intro.php&param=oneparam' => [
1388-
'/cms/typo3/alt_intro.php&param=oneparam',
1387+
'/cms/foo/%3Fbar?baz' => [
1388+
'/cms/foo/%3Fbar?baz',
13891389
'localhost',
13901390
'/cms/',
13911391
],
1392-
'/cms/typo3/alt_intro.php&param=oneparam with spaces' => [
1393-
'/cms/typo3/alt_intro.php&param=oneparam with spaces',
1392+
'/cms/typo3/alt_intro.php?param=oneparam' => [
1393+
'/cms/typo3/alt_intro.php?param=oneparam',
13941394
'localhost',
13951395
'/cms/',
13961396
],
1397-
'/cms/typo3/alt_intro.php&param=oneparam with spaces&normalparam=2' => [
1398-
'/cms/typo3/alt_intro.php&param=oneparam with spaces',
1397+
'/cms/typo3/alt_intro.php?param=oneparam+with+spaces' => [
1398+
'/cms/typo3/alt_intro.php?param=oneparam+with+spaces',
1399+
'localhost',
1400+
'/cms/',
1401+
],
1402+
'/cms/typo3/alt_intro.php?param=oneparam%20with%20spaces' => [
1403+
'/cms/typo3/alt_intro.php?param=oneparam%20with%20spaces',
1404+
'localhost',
1405+
'/cms/',
1406+
],
1407+
'/cms/typo3/alt_intro.php?param=oneparam%20with%20spaces&normalparam=2' => [
1408+
'/cms/typo3/alt_intro.php?param=oneparam%20with%20spaces',
13991409
'localhost',
14001410
'/cms/',
14011411
],
@@ -1453,7 +1463,28 @@ public static function sanitizeLocalUrlInvalidDataProvider(): array
14531463
'empty string' => [''],
14541464
'http domain' => ['http://www.google.de/'],
14551465
'https domain' => ['https://www.google.de/'],
1466+
'https domain with' => ['https://www.google.de/'],
1467+
'https domain with escape at start' => ['https:\\//www.google.de'],
1468+
'https domain with escape in between' => ['https:/\\/www.google.de'],
1469+
'https domain with escape after' => ['https://\\www.google.de'],
1470+
'https domain with escape instead of slash' => ['https:/\\www.google.de'],
1471+
'https domain with double backslash' => ['https:\\\\www.google.de'],
1472+
'https domain with double backslash and one slash' => ['https:\\/www.google.de'],
1473+
'https domain with quad slash' => ['https:////www.google.de'],
1474+
'https domain with newline' => ["htt\nps://www.google.de"],
14561475
'domain without schema' => ['//www.google.de/'],
1476+
'domain without schema escape at start' => ['\\//www.google.de', true],
1477+
'domain without schema escape in between' => ['/\\/www.google.de', true],
1478+
'domain without schema escape after' => ['//\\www.google.de', true],
1479+
'domain without schema escape instead of slash' => ['/\\www.google.de', true],
1480+
'domain without schema with double backslash' => ['\\\\www.google.de', true],
1481+
'domain without schema with double backslash and one slash' => ['\\/www.google.de', true],
1482+
'domain without schema with quad slash' => ['////www.google.de'],
1483+
'domain without schema with newline' => ["/\n/www.google.de", true],
1484+
'domain without schema with EOT' => ["\x04//google.de", true],
1485+
'domain without schema with bell' => ["\x07//google.de", true],
1486+
'domain without schema with backspace' => ["\x08//google.de", true],
1487+
'domain without schema with form feed' => ["\x0c//google.de", true],
14571488
'XSS attempt' => ['" onmouseover="alert(123)"'],
14581489
'invalid URL, UNC path' => ['\\\\foo\\bar\\'],
14591490
'invalid URL, HTML break out attempt' => ['" >blabuubb'],
@@ -1463,6 +1494,7 @@ public static function sanitizeLocalUrlInvalidDataProvider(): array
14631494
'relative URL with location header injection attempt (not known to work) via vertical white space' => ["\v" . '//evil.site/'],
14641495
'HTTP header smuggling attempt' => ["/\r\nX-Injected: evil", true],
14651496
'null-byte break out attempt' => ["http\x00://www.google.de"],
1497+
'path invalid because it contains unencoded spaces' => ['/cms/typo3/alt_intro.php&param=oneparam with spaces', true],
14661498
];
14671499
}
14681500

0 commit comments

Comments
 (0)