diff --git a/libraries/src/Uri/Uri.php b/libraries/src/Uri/Uri.php index 54740acf3a00e..88fe059e0f959 100644 --- a/libraries/src/Uri/Uri.php +++ b/libraries/src/Uri/Uri.php @@ -103,8 +103,12 @@ public static function getInstance($uri = 'SERVER') } } - // Extra cleanup to remove invalid chars in the URL to prevent injections through the Host header + /* + * Extra cleanup to remove invalid chars in the URL to prevent injections through the Host header. + * Control characters are never valid in a URL, so they are removed instead of being encoded. + */ $theURI = str_replace(["'", '"', '<', '>'], ['%27', '%22', '%3C', '%3E'], $theURI); + $theURI = (string) preg_replace('/[\x00-\x1F\x7F]/', '', $theURI); } else { // We were given a URI $theURI = $uri; diff --git a/tests/Unit/Libraries/Cms/Uri/UriTest.php b/tests/Unit/Libraries/Cms/Uri/UriTest.php index c3de922466779..7710c7f78ab53 100644 --- a/tests/Unit/Libraries/Cms/Uri/UriTest.php +++ b/tests/Unit/Libraries/Cms/Uri/UriTest.php @@ -344,6 +344,33 @@ public function testIsInternal3rdPartyDevs(): void ); } + /** + * Test hardening of Uri::getInstance against control characters in the server URI + * + * @return void + * + * @covers Uri::getInstance + */ + public function testGetInstanceRemovesControlCharactersFromServerUri(): void + { + Uri::reset(); + + $_SERVER['HTTP_HOST'] = "www.example.com\r\n"; + $_SERVER['SCRIPT_NAME'] = '/joomla/index.php'; + $_SERVER['PHP_SELF'] = '/joomla/index.php'; + $_SERVER['REQUEST_URI'] = "/joomla/index.php\x00?var=value 10"; + + $this->object = new Uri(); + + $uri = Uri::getInstance()->toString(['scheme', 'host', 'port', 'path', 'query']); + + $this->assertSame( + 'http://www.example.com/joomla/index.php?var=value 10', + $uri, + 'Control characters should be stripped from the URI built from the server variables' + ); + } + /** * Test hardening of Uri::isInternal against non internal links *