CVE-2023-24814 (published 2023-02-07T19:15Z)

TYPO3 is a free and open source Content Management Framework released under the GNU General Public License. In affected versions the TYPO3 core component `GeneralUtility::getIndpEnv()` uses the unfiltered server environment variable `PATH_INFO`, which allows attackers to inject malicious content. In combination with the TypoScript setting `config.absRefPrefix=auto`, attackers can inject malicious HTML code to pages that have not been rendered and cached, yet. As a result, injected values would be cached and delivered to other website visitors (persisted cross-site scripting). Individual code which relies on the resolved value of `GeneralUtility::getIndpEnv('SCRIPT_NAME')` and corresponding usages (as shown below) are vulnerable as well. Additional investigations confirmed that at least Apache web server deployments using CGI (FPM, FCGI/FastCGI, and similar) are affected. However, there still might be the risk that other scenarios like nginx, IIS, or Apache/mod_php are vulnerable. The usage of server environment variable `PATH_INFO` has been removed from corresponding processings in `GeneralUtility::getIndpEnv()`. Besides that, the public property `TypoScriptFrontendController::$absRefPrefix` is encoded for both being used as a URI component and for being used as a prefix in an HTML context. This mitigates the cross-site scripting vulnerability. Users are advised to update to TYPO3 versions 8.7.51 ELTS, 9.5.40 ELTS, 10.4.35 LTS, 11.5.23 LTS and 12.2.0 which fix this problem. For users who are unable to patch in a timely manner the TypoScript setting `config.absRefPrefix` should at least be set to a static path value, instead of using auto - e.g. `config.absRefPrefix=/`. This workaround **does not fix all aspects of the vulnerability**, and is just considered to be an intermediate mitigation to the most prominent manifestation.

CVSS v3 base score: 6.1, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N)

Weakness information:
cwe_id: CWE-79
cwe_name: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
extended_description: 
            Cross-site scripting (XSS) vulnerabilities occur when:
            
               Untrusted data enters a web application, typically from a web request.
               The web application dynamically generates a web page that contains this untrusted data.
               During page generation, the application does not prevent the data from containing content that is executable by a web browser, such as JavaScript, HTML tags, HTML attributes, mouse events, Flash, ActiveX, etc.
               A victim visits the generated web page through a web browser, which contains malicious script that was injected using the untrusted data.
               Since the script comes from a web page that was sent by the web server, the victim's web browser executes the malicious script in the context of the web server's domain.
               This effectively violates the intention of the web browser's same-origin policy, which states that scripts in one domain should not be able to access resources or run code in a different domain.
            
            There are three main kinds of XSS:
            
               
                  Type 1: Reflected XSS (or Non-Persistent) - 
         			The server reads data directly from the HTTP request and reflects it back in the HTTP response. Reflected XSS exploits occur when an attacker causes a victim to supply dangerous content to a vulnerable web application, which is then reflected back to the victim and executed by the web browser. The most common mechanism for delivering malicious content is to include it as a parameter in a URL that is posted publicly or e-mailed directly to the victim. URLs constructed in this manner constitute the core of many phishing schemes, whereby an attacker convinces a victim to visit a URL that refers to a vulnerable site. After the site reflects the attacker's content back to the victim, the content is executed by the victim's browser.
               
                  Type 2: Stored XSS (or Persistent) - 
               The application stores dangerous data in a database, message forum, visitor log, or other trusted data store. At a later time, the dangerous data is subsequently read back into the application and included in dynamic content. From an attacker's perspective, the optimal place to inject malicious content is in an area that is displayed to either many users or particularly interesting users. Interesting users typically have elevated privileges in the application or interact with sensitive data that is valuable to the attacker. If one of these users executes malicious content, the attacker may be able to perform privileged operations on behalf of the user or gain access to sensitive data belonging to the user. For example, the attacker might inject XSS into a log message, which might not be handled properly when an administrator views the logs.
            
               
                  Type 0: DOM-Based XSS - 
               In DOM-based XSS, the client performs the injection of XSS into the page; in the other types, the server performs the injection. DOM-based XSS generally involves server-controlled, trusted script that is sent to the client, such as Javascript that performs sanity checks on a form before the user submits it. If the server-supplied script processes user-supplied data and then injects it back into the web page (such as with dynamic HTML), then DOM-based XSS is possible.
            
            
            Once the malicious script is injected, the attacker can perform a variety of malicious activities. The attacker could transfer private information, such as cookies that may include session information, from the victim's machine to the attacker. The attacker could send malicious requests to a web site on behalf of the victim, which could be especially dangerous to the site if the victim has administrator privileges to manage that site. Phishing attacks could be used to emulate trusted web sites and trick the victim into entering a password, allowing the attacker to compromise the victim's account on that web site. Finally, the script could exploit a vulnerability in the web browser itself possibly taking over the victim's machine, sometimes referred to as "drive-by hacking."
            In many cases, the attack can be launched without the victim even being aware of it. Even with careful users, attackers frequently use a variety of methods to encode the malicious portion of the attack, such as URL encoding or Unicode, so the request looks less suspicious.
         
         

Fix information:
repo_url: https://github.com/TYPO3/typo3
commit_details: repo_url: https://github.com/TYPO3/typo3
author: Benjamin Franzke
author_date: 2023-02-07 10:25:07+01:00
msg: [SECURITY] Prevent XSS due to wrong PATH_INFO evaluation

As already started in #88304 (but only for NormalizedParams)
and later reverted in #89312 (because of cgi-bin problems),
PATH_INFO is no longer considered as a preferable SCRIPT_NAME
alternative. All known server configurations set SCRIPT_NAME
these days to a proper value when cgi.fix_pathinfo is set.

The fallback to PATH_INFO has been introduced with
the initial revision of TYPO3 and isn't needed at all nowadays,
it's actually wrong, as a REQUEST_URI like /index.php/foo/bar
would incorrectly be interpreted as $scriptName == "/foo/bar",
which let's all calculations on $scriptName fail and
even leads to XSS where values derived from $scriptName are
printed without being escaped.

Also any ORIG_SCRIPT_NAME evaluation is dropped, as this variable
contains the SCRIPT_NAME that was set by the webserver configuration
before PHP applied cgi.fix_pathinfo. Using ORIG_SCRIPT_NAME
effectively meant bypassing PHP's pathinfo fix. It usually contains
the cgi-wrapper paths, which is why PATH_INFO was used to overrule
wrong ORIG_SCRIPT_NAME values.

GeneralUtility::getIndpEnv('PATH_INFO') is adapted to trust the
servers PATH_INFO information, now that we no longer allow
servers to send SCRIPT_NAME as PATH_INFO (we enforce
cgi.fix_pathinfo=1 for CGI installations).

The normalized SCRIPT_NAME is now adapted to be encoded as a URL
path by default, as all TYPO3 usages expect this to be an URL path.
Note that $_SERVER['SCRIPT_NAME'] refers to the servers file
system path, not the URL encoded value.

This SCRIPT_NAME sanitization actually enables:

a) TYPO3 to be run in a subfolder that contains characters
that need URL encoding
e.g. `/test:site/` – url encoded that'd be `/test3Asite/`.

b) prevention of XSS in case third party extensions
missed to escape any URL that is derived from SCRIPT_NAME
(while making sure that properly escaped
output is not double escaped)

Resolves: #99651
Related: #88304
Related: #89312
Releases: main, 11.5, 10.4
Change-Id: Ief95253d764665db5182a15ce8ffd02ea02ee61e
Security-Bulletin: TYPO3-CORE-SA-2023-001
Security-References: CVE-2023-24814
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/77739
Tested-by: Oliver Hader <oliver.hader@typo3.org>
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
repository: repo_url: https://github.com/TYPO3/typo3
repo_name: TYPO3/typo3
description: The TYPO3 Core - Enterprise Content Management System. Synchronized mirror of https://review.typo3.org/q/project:Packages/TYPO3.CMS
repo_language: PHP
owner: TYPO3
file_changes: filename: SystemEnvironmentBuilder.php
change_type: ModificationType.MODIFY
diff: @@ -255,23 +255,17 @@ class SystemEnvironmentBuilder
     }
 
     /**
-     * Calculate path to entry script if not in cli mode.
-     *
-     * Depending on the environment, the script path is found in different $_SERVER variables.
+     * Return path to entry script if not in cli mode.
      *
      * @return string Absolute path to entry script
      */
     protected static function getPathThisScriptNonCli()
     {
-        $isCgi = Environment::isRunningOnCgiServer();
-        if ($isCgi && Environment::usesCgiFixPathInfo()) {
-            return $_SERVER['SCRIPT_FILENAME'];
-        }
-        $cgiPath = $_SERVER['ORIG_PATH_TRANSLATED'] ?? $_SERVER['PATH_TRANSLATED'] ?? '';
-        if ($cgiPath && $isCgi) {
-            return $cgiPath;
+        if (Environment::isRunningOnCgiServer() && !Environment::usesCgiFixPathInfo()) {
+            throw new \Exception('TYPO3 does only support being used with cgi.fix_pathinfo=1 on CGI server APIs.', 1675108421);
         }
-        return $_SERVER['ORIG_SCRIPT_FILENAME'] ?? $_SERVER['SCRIPT_FILENAME'];
+
+        return $_SERVER['SCRIPT_FILENAME'];
     }
 
     /**

programming_language: PHP
filename: NormalizedParams.php
change_type: ModificationType.MODIFY
diff: @@ -311,12 +311,13 @@ class NormalizedParams
         $requestHost = $this->requestHost = ($isHttps ? 'https://' : 'http://') . $httpHost;
         $requestHostOnly = $this->requestHostOnly = self::determineRequestHostOnly($httpHost);
         $this->requestPort = self::determineRequestPort($httpHost, $requestHostOnly);
-        $scriptName = $this->scriptName = self::determineScriptName(
+        $scriptNameOnFileSystem = self::determineScriptName(
             $serverParams,
             $configuration,
             $isHttps,
             $isBehindReverseProxy
         );
+        $scriptName = $this->scriptName = self::encodeFileSystemPathComponentForUrlPath($scriptNameOnFileSystem);
         $requestUri = $this->requestUri = self::determineRequestUri(
             $serverParams,
             $configuration,
@@ -329,7 +330,7 @@ class NormalizedParams
         $requestDir = $this->requestDir = $requestHost . GeneralUtility::dirname($scriptName) . '/';
         $this->remoteAddress = self::determineRemoteAddress($serverParams, $configuration, $isBehindReverseProxy);
         $scriptFilename = $this->scriptFilename = $pathThisScript;
-        $this->documentRoot = self::determineDocumentRoot($scriptName, $scriptFilename);
+        $this->documentRoot = self::determineDocumentRoot($scriptNameOnFileSystem, $scriptFilename);
         $siteUrl = $this->siteUrl = self::determineSiteUrl($requestDir, $pathThisScript, $pathSite . '/');
         $this->sitePath = self::determineSitePath($requestHost, $siteUrl);
         $this->siteScript = self::determineSiteScript($requestUrl, $siteUrl);
@@ -344,6 +345,11 @@ class NormalizedParams
         $this->queryString = $serverParams['QUERY_STRING'] ?? '';
     }
 
+    private static function encodeFileSystemPathComponentForUrlPath(string $path): string
+    {
+        return implode('/', array_map('rawurlencode', explode('/', $path)));
+    }
+
     /**
      * @return string Sanitized HTTP_HOST value host[:port]
      */
@@ -632,17 +638,7 @@ class NormalizedParams
         bool $isHttps,
         bool $isBehindReverseProxy
     ): string {
-        // see https://forge.typo3.org/issues/89312
-        // When using a CGI wrapper to dispatch the PHP process `ORIG_SCRIPT_NAME`
-        // contains the name of the wrapper script (which is most probably outside
-        // the TYPO3's project root) and leads to invalid prefixes, e.g. resolving
-        // the `siteUrl` incorrectly as `http://ip10.local/fcgi/` instead of
-        // actual `http://ip10.local/`
-        $possiblePathInfo = ($serverParams['ORIG_PATH_INFO'] ?? '') ?: ($serverParams['PATH_INFO'] ?? '');
-        $possibleScriptName = ($serverParams['ORIG_SCRIPT_NAME'] ?? '') ?: ($serverParams['SCRIPT_NAME'] ?? '');
-        $scriptName = Environment::isRunningOnCgiServer() && $possiblePathInfo
-            ? $possiblePathInfo
-            : $possibleScriptName;
+        $scriptName = $serverParams['SCRIPT_NAME'] ?? '';
         if ($isBehindReverseProxy) {
             // Add a prefix if TYPO3 is behind a proxy: ext-domain.com => int-server.com/prefix
             if ($isHttps && !empty($configuration['reverseProxyPrefixSSL'])) {
@@ -778,11 +774,11 @@ class NormalizedParams
     /**
      * Calculate absolute path to web document root
      *
-     * @param string $scriptName Entry script path of URI, without domain and without query parameters, with leading /
+     * @param string $scriptNameOnFileSystem Entry script path of URI on file system, without domain and without query parameters, with leading /
      * @param string $scriptFilename Absolute path to entry script on server filesystem
      * @return string Path to document root with trailing slash
      */
-    protected static function determineDocumentRoot(string $scriptName, string $scriptFilename): string
+    protected static function determineDocumentRoot(string $scriptNameOnFileSystem, string $scriptFilename): string
     {
         // Get the web root (it is not the root of the TYPO3 installation)
         // Some CGI-versions (LA13CGI) and mod-rewrite rules on MODULE versions will deliver a 'wrong'
@@ -790,7 +786,7 @@ class NormalizedParams
         // disturb this as well. Therefore the DOCUMENT_ROOT is always calculated as the SCRIPT_FILENAME
         // minus the end part shared with SCRIPT_NAME.
         $webDocRoot = '';
-        $scriptNameArray = explode('/', strrev($scriptName));
+        $scriptNameArray = explode('/', strrev($scriptNameOnFileSystem));
         $scriptFilenameArray = explode('/', strrev($scriptFilename));
         $path = [];
         foreach ($scriptNameArray as $segmentNumber => $segment) {

programming_language: PHP
filename: GeneralUtility.php
change_type: ModificationType.MODIFY
diff: @@ -2310,10 +2310,7 @@ class GeneralUtility
         $retVal = '';
         switch ((string)$getEnvName) {
             case 'SCRIPT_NAME':
-                $retVal = Environment::isRunningOnCgiServer()
-                    && (($_SERVER['ORIG_PATH_INFO'] ?? false) ?: ($_SERVER['PATH_INFO'] ?? false))
-                        ? (($_SERVER['ORIG_PATH_INFO'] ?? '') ?: ($_SERVER['PATH_INFO'] ?? ''))
-                        : (($_SERVER['ORIG_SCRIPT_NAME'] ?? '') ?: ($_SERVER['SCRIPT_NAME'] ?? ''));
+                $retVal = $_SERVER['SCRIPT_NAME'] ?? '';
                 // Add a prefix if TYPO3 is behind a proxy: ext-domain.com => int-server.com/prefix
                 if (self::cmpIP($_SERVER['REMOTE_ADDR'] ?? '', $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'] ?? '')) {
                     if (self::getIndpEnv('TYPO3_SSL') && $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefixSSL']) {
@@ -2322,6 +2319,7 @@ class GeneralUtility
                         $retVal = $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefix'] . $retVal;
                     }
                 }
+                $retVal = self::encodeFileSystemPathComponentForUrlPath($retVal);
                 break;
             case 'SCRIPT_FILENAME':
                 $retVal = Environment::getCurrentScript();
@@ -2350,17 +2348,7 @@ class GeneralUtility
                 }
                 break;
             case 'PATH_INFO':
-                // $_SERVER['PATH_INFO'] != $_SERVER['SCRIPT_NAME'] is necessary because some servers (Windows/CGI)
-                // are seen to set PATH_INFO equal to script_name
-                // Further, there must be at least one '/' in the path - else the PATH_INFO value does not make sense.
-                // IF 'PATH_INFO' never works for our purpose in TYPO3 with CGI-servers,
-                // then 'PHP_SAPI=='cgi'' might be a better check.
-                // Right now strcmp($_SERVER['PATH_INFO'], GeneralUtility::getIndpEnv('SCRIPT_NAME')) will always
-                // return FALSE for CGI-versions, but that is only as long as SCRIPT_NAME is set equal to PATH_INFO
-                // because of PHP_SAPI=='cgi' (see above)
-                if (!Environment::isRunningOnCgiServer()) {
-                    $retVal = $_SERVER['PATH_INFO'] ?? '';
-                }
+                $retVal = $_SERVER['PATH_INFO'] ?? '';
                 break;
             case 'TYPO3_REV_PROXY':
                 $retVal = self::cmpIP($_SERVER['REMOTE_ADDR'] ?? '', $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP']);
@@ -2433,7 +2421,10 @@ class GeneralUtility
                 // Some CGI-versions (LA13CGI) and mod-rewrite rules on MODULE versions will deliver a 'wrong' DOCUMENT_ROOT (according to our description). Further various aliases/mod_rewrite rules can disturb this as well.
                 // Therefore the DOCUMENT_ROOT is now always calculated as the SCRIPT_FILENAME minus the end part shared with SCRIPT_NAME.
                 $SFN = self::getIndpEnv('SCRIPT_FILENAME');
-                $SN_A = explode('/', strrev(self::getIndpEnv('SCRIPT_NAME')));
+                // Use rawurldecode to reverse the result of self::encodeFileSystemPathComponentForUrlPath()
+                // which has been applied to getIndpEnv(SCRIPT_NAME) for web URI usage.
+                // We compare with a file system path (SCRIPT_FILENAME) in here and therefore need to undo the encoding.
+                $SN_A = array_map('rawurldecode', explode('/', strrev(self::getIndpEnv('SCRIPT_NAME'))));
                 $SFN_A = explode('/', strrev($SFN));
                 $acc = [];
                 foreach ($SN_A as $kk => $vv) {
@@ -2558,6 +2549,11 @@ class GeneralUtility
         return !empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off';
     }
 
+    protected static function encodeFileSystemPathComponentForUrlPath(string $path): string
+    {
+        return implode('/', array_map('rawurlencode', explode('/', $path)));
+    }
+
     /*************************
      *
      * TYPO3 SPECIFIC FUNCTIONS

programming_language: PHP
filename: ApplicationEnvironment.php
change_type: ModificationType.MODIFY
diff: @@ -145,7 +145,6 @@ final class ApplicationEnvironment extends BackendEnvironment
             'SCRIPT_NAME' => '/typo3/index.php',
             'PHP_SELF' => '/typo3/index.php',
             'SCRIPT_FILENAME' => $docRoot . '/index.php',
-            'PATH_TRANSLATED' => $docRoot . '/index.php',
             'QUERY_STRING' => $requestUrlParts['query'] ?? '',
             'REQUEST_URI' => $requestUrlParts['path'] . (isset($requestUrlParts['query']) ? '?' . $requestUrlParts['query'] : ''),
             'REQUEST_METHOD' => $method,

programming_language: PHP
filename: NormalizedParamsTest.php
change_type: ModificationType.MODIFY
diff: @@ -360,77 +360,19 @@ class NormalizedParamsTest extends UnitTestCase
                 [],
                 '',
             ],
-            'use ORIG_SCRIPT_NAME if ORIG_PATH_INFO is set but empty' => [
-                [
-                    'ORIG_PATH_INFO' => '',
-                    'PATH_INFO' => '',
-                    'ORIG_SCRIPT_NAME' => '/orig/script/name.php',
-                    'SCRIPT_NAME' => '/script/name.php',
-                ],
-                [],
-                '/orig/script/name.php',
-            ],
-            'use ORIG_SCRIPT_NAME if PATH_INFO is set but empty' => [
-                [
-                    'PATH_INFO' => '',
-                    'ORIG_SCRIPT_NAME' => '/orig/script/name.php',
-                    'SCRIPT_NAME' => '/script/name.php',
-                ],
-                [],
-                '/orig/script/name.php',
-            ],
-            'use SCRIPT_NAME if ORIG_PATH_INFO is set but empty' => [
-                [
-                    'ORIG_PATH_INFO' => '',
-                    'PATH_INFO' => '',
-                    'ORIG_SCRIPT_NAME' => '',
-                    'SCRIPT_NAME' => '/script/name.php',
-                ],
-                [],
-                '/script/name.php',
-            ],
-            'use SCRIPT_NAME if PATH_INFO is set but empty' => [
-                [
-                    'PATH_INFO' => '',
-                    'ORIG_SCRIPT_NAME' => '',
-                    'SCRIPT_NAME' => '/script/name.php',
-                ],
-                [],
-                '/script/name.php',
-            ],
-            'use SCRIPT_NAME if ORIG_PATH_INFO is set' => [
-                [
-                    'ORIG_PATH_INFO' => '/foo/bar',
-                    'PATH_INFO' => '',
-                    'ORIG_SCRIPT_NAME' => '',
-                    'SCRIPT_NAME' => '/script/name.php',
-                ],
-                [],
-                '/script/name.php',
-            ],
-            'use SCRIPT_NAME if PATH_INFO is set' => [
+            'use SCRIPT_NAME' => [
                 [
-                    'PATH_INFO' => '/foo/bar',
-                    'ORIG_SCRIPT_NAME' => '',
                     'SCRIPT_NAME' => '/script/name.php',
                 ],
                 [],
                 '/script/name.php',
             ],
-            'use ORIG_SCRIPT_NAME' => [
-                [
-                    'ORIG_SCRIPT_NAME' => '/orig/script/name.php',
-                    'SCRIPT_NAME' => '/script/name.php',
-                ],
-                [],
-                '/orig/script/name.php',
-            ],
-            'use SCRIPT_NAME' => [
+            'apply URL encoding to SCRIPT_NAME' => [
                 [
-                    'SCRIPT_NAME' => '/script/name.php',
+                    'SCRIPT_NAME' => '/test:site/script/name.php',
                 ],
                 [],
-                '/script/name.php',
+                '/test%3Asite/script/name.php',
             ],
             'add proxy ssl prefix' => [
                 [
@@ -497,6 +439,14 @@ class NormalizedParamsTest extends UnitTestCase
                 [],
                 '/typo3/index.php?parameter=foo/bar&id=42',
             ],
+            'use query string and script name in special subdirectory if REQUEST_URI is not set' => [
+                [
+                    'QUERY_STRING' => 'parameter=foo/bar&id=42',
+                    'SCRIPT_NAME' => '/sub:dir/typo3/index.php',
+                ],
+                [],
+                '/sub%3Adir/typo3/index.php?parameter=foo/bar&id=42',
+            ],
             'prefix with proxy prefix with ssl if using REQUEST_URI' => [
                 [
                     'HTTP_HOST' => 'www.domain.com',
@@ -905,7 +855,6 @@ class NormalizedParamsTest extends UnitTestCase
         $serverParams = [
             'SCRIPT_NAME' => '/typo3/index.php',
             'HTTP_HOST' => 'www.domain.com',
-            'PATH_INFO' => '/typo3/index.php',
         ];
         $pathThisScript = '/var/www/myInstance/Web/typo3/index.php';
         $pathSite = '/var/www/myInstance/Web';
@@ -978,7 +927,8 @@ class NormalizedParamsTest extends UnitTestCase
         return [
             'not in a sub directory' => [
                 [
-                    'SCRIPT_NAME' => '/typo3/index.php?id=42&foo=bar',
+                    'SCRIPT_NAME' => '/typo3/index.php',
+                    'REQUEST_URI' => '/typo3/index.php?id=42&foo=bar',
                     'HTTP_HOST' => 'www.domain.com',
                 ],
                 '/var/www/myInstance/Web/typo3/index.php',
@@ -987,7 +937,8 @@ class NormalizedParamsTest extends UnitTestCase
             ],
             'in a sub directory' => [
                 [
-                    'SCRIPT_NAME' => '/some/sub/dir/typo3/index.php?id=42&foo=bar',
+                    'SCRIPT_NAME' => '/some/sub/dir/typo3/index.php',
+                    'REQUEST_URI' => '/some/sub/dir/typo3/index.php?id=42&foo=bar',
                     'HTTP_HOST' => 'www.domain.com',
                 ],
                 '/var/www/myInstance/Web/typo3/index.php',
@@ -1023,9 +974,9 @@ class NormalizedParamsTest extends UnitTestCase
     public function getPathInfoReturnsExpectedValue(): void
     {
         $serverParams = [
-            'PATH_INFO' => '/typo3/index.php',
+            'PATH_INFO' => '/foo/bar',
         ];
-        $expected = '/typo3/index.php';
+        $expected = '/foo/bar';
         $serverRequestParameters = new NormalizedParams($serverParams, [], '', '');
         self::assertSame($expected, $serverRequestParameters->getPathInfo());
     }

programming_language: TypeScript
filename: WebProcessorTest.php
change_type: ModificationType.MODIFY
diff: @@ -30,9 +30,8 @@ class WebProcessorTest extends UnitTestCase
      */
     public function webProcessorAddsWebDataToLogRecord(): void
     {
-        $_SERVER['PATH_INFO'] = '';
         $_SERVER['REQUEST_URI'] = '';
-        $_SERVER['ORIG_SCRIPT_NAME'] = '';
+        $_SERVER['SCRIPT_NAME'] = '';
         $_SERVER['REMOTE_ADDR'] = '';
         $_SERVER['QUERY_STRING'] = '';
         $_SERVER['SSL_SESSION_ID'] = '';

programming_language: PHP
filename: RedirectUrlValidatorTest.php
change_type: ModificationType.MODIFY
diff: @@ -64,7 +64,7 @@ class RedirectUrlValidatorTest extends UnitTestCase
      */
     protected function setUpFakeSitePathAndHost(): void
     {
-        $_SERVER['ORIG_PATH_INFO'] = $_SERVER['PATH_INFO'] = $_SERVER['ORIG_SCRIPT_NAME'] = $_SERVER['SCRIPT_NAME'] = $this->testSitePath . 'index.php';
+        $_SERVER['SCRIPT_NAME'] = $this->testSitePath . 'index.php';
         $_SERVER['HTTP_HOST'] = $this->testHostName;
 
         $request = ServerRequestFactory::fromGlobals();

programming_language: PHP
filename: TypoScriptFrontendController.php
change_type: ModificationType.MODIFY
diff: @@ -2423,6 +2423,7 @@ class TypoScriptFrontendController implements LoggerAwareInterface
         if (!$this->absRefPrefix) {
             return;
         }
+        $encodedAbsRefPrefix = htmlspecialchars($this->absRefPrefix, ENT_QUOTES | ENT_HTML5);
         $search = [
             '"_assets/',
             '"typo3temp/',
@@ -2430,16 +2431,16 @@ class TypoScriptFrontendController implements LoggerAwareInterface
             '"' . PathUtility::stripPathSitePrefix(Environment::getFrameworkBasePath()) . '/',
         ];
         $replace = [
-            '"' . $this->absRefPrefix . '_assets/',
-            '"' . $this->absRefPrefix . 'typo3temp/',
-            '"' . $this->absRefPrefix . PathUtility::stripPathSitePrefix(Environment::getExtensionsPath()) . '/',
-            '"' . $this->absRefPrefix . PathUtility::stripPathSitePrefix(Environment::getFrameworkBasePath()) . '/',
+            '"' . $encodedAbsRefPrefix . '_assets/',
+            '"' . $encodedAbsRefPrefix . 'typo3temp/',
+            '"' . $encodedAbsRefPrefix . PathUtility::stripPathSitePrefix(Environment::getExtensionsPath()) . '/',
+            '"' . $encodedAbsRefPrefix . PathUtility::stripPathSitePrefix(Environment::getFrameworkBasePath()) . '/',
         ];
         // Process additional directories
         $directories = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['FE']['additionalAbsRefPrefixDirectories'], true);
         foreach ($directories as $directory) {
             $search[] = '"' . $directory;
-            $replace[] = '"' . $this->absRefPrefix . $directory;
+            $replace[] = '"' . $encodedAbsRefPrefix . $directory;
         }
         $this->content = str_replace(
             $search,

programming_language: PHP