CVE-2021-41267 (published 2021-11-24T19:15Z)

Symfony/Http-Kernel is the HTTP kernel component for Symfony, a PHP framework for web and console applications and a set of reusable PHP components. Headers that are not part of the "trusted_headers" allowed list are ignored and protect users from "Cache poisoning" attacks. In Symfony 5.2, maintainers added support for the `X-Forwarded-Prefix` headers, but this header was accessible in SubRequest, even if it was not part of the "trusted_headers" allowed list. An attacker could leverage this opportunity to forge requests containing a `X-Forwarded-Prefix` header, leading to a web cache poisoning issue. Versions 5.3.12 and later have a patch to ensure that the `X-Forwarded-Prefix` header is not forwarded to subrequests when it is not trusted.

Severity: MEDIUM
CVSS v2 base score: 4.3 (AV:N/AC:M/Au:N/C:N/I:P/A:N)
CVSS v3 base score: 6.5, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N)

Weakness information:
cwe_id: CWE-444
cwe_name: Inconsistent Interpretation of HTTP Requests ('HTTP Request/Response Smuggling')
description: The product acts as an intermediary HTTP agent
         (such as a proxy or firewall) in the data flow between two
         entities such as a client and server, but it does not
         interpret malformed HTTP requests or responses in ways that
         are consistent with how the messages will be processed by
         those entities that are at the ultimate destination.
extended_description: 
	   HTTP requests or responses ("messages") can be
	   malformed or unexpected in ways that cause web servers or
	   clients to interpret the messages in different ways than
	   intermediary HTTP agents such as load balancers, reverse
	   proxies, web caching proxies, application firewalls,
	   etc. For example, an adversary may be able to add duplicate
	   or different header fields that a client or server might
	   interpret as one set of messages, whereas the intermediary
	   might interpret the same sequence of bytes as a different
	   set of messages. For example, discrepancies can arise in
	   how to handle duplicate headers like two Transfer-encoding
	   (TE) or two Content-length (CL), or the malicious HTTP
	   message will have different headers for TE and
	   CL.
	   The inconsistent parsing and interpretation of messages
	   can allow the adversary to "smuggle" a message to the
	   client/server without the intermediary being aware of it.
	   This weakness is usually the result of the usage
	   of outdated or incompatible HTTP protocol versions in the
	   HTTP agents.
         
         

Fix information:
repo_url: https://github.com/symfony/symfony
commit_details: repo_url: https://github.com/symfony/symfony
author: Jérémy Derussé
author_date: 2021-10-09 14:10:44+02:00
msg: Fix missing extra trusted header in sub-request
repository: repo_url: https://github.com/symfony/symfony
repo_name: symfony/symfony
description: The Symfony PHP framework
repo_language: PHP
owner: symfony
file_changes: filename: SubRequestHandler.php
change_type: ModificationType.MODIFY
diff: @@ -38,6 +38,7 @@ class SubRequestHandler
                 'X_FORWARDED_HOST' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_HOST,
                 'X_FORWARDED_PROTO' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PROTO,
                 'X_FORWARDED_PORT' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PORT,
+                'X_FORWARDED_PREFIX' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PREFIX,
             ];
             foreach (array_filter($trustedHeaders) as $name => $key) {
                 $request->headers->remove($name);

programming_language: PHP
filename: SubRequestHandlerTest.php
change_type: ModificationType.MODIFY
diff: @@ -42,6 +42,7 @@ class SubRequestHandlerTest extends TestCase
         $request->headers->set('X-Forwarded-Host', 'Good');
         $request->headers->set('X-Forwarded-Port', '1234');
         $request->headers->set('X-Forwarded-Proto', 'https');
+        $request->headers->set('X-Forwarded-Prefix', '/admin');
 
         $kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) {
             $this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR'));
@@ -49,6 +50,7 @@ class SubRequestHandlerTest extends TestCase
             $this->assertSame('Good', $request->headers->get('X-Forwarded-Host'));
             $this->assertSame('1234', $request->headers->get('X-Forwarded-Port'));
             $this->assertSame('https', $request->headers->get('X-Forwarded-Proto'));
+            $this->assertSame('/admin', $request->headers->get('X-Forwarded-Prefix'));
         });
 
         SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MAIN_REQUEST, true);
@@ -64,6 +66,7 @@ class SubRequestHandlerTest extends TestCase
         $request->headers->set('X-Forwarded-Host', 'Evil');
         $request->headers->set('X-Forwarded-Port', '1234');
         $request->headers->set('X-Forwarded-Proto', 'http');
+        $request->headers->set('X-Forwarded-Prefix', '/admin');
         $request->headers->set('Forwarded', 'Evil2');
 
         $kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) {
@@ -72,6 +75,7 @@ class SubRequestHandlerTest extends TestCase
             $this->assertFalse($request->headers->has('X-Forwarded-Host'));
             $this->assertFalse($request->headers->has('X-Forwarded-Port'));
             $this->assertFalse($request->headers->has('X-Forwarded-Proto'));
+            $this->assertFalse($request->headers->has('X-Forwarded-Prefix'));
             $this->assertSame('for="10.0.0.1";host="localhost";proto=http', $request->headers->get('Forwarded'));
         });
 
@@ -112,12 +116,14 @@ class SubRequestHandlerTest extends TestCase
         $request->headers->set('X-Forwarded-For', '10.0.0.2');
         $request->headers->set('X-Forwarded-Host', 'foo.bar');
         $request->headers->set('X-Forwarded-Proto', 'https');
+        $request->headers->set('X-Forwarded-Prefix', '/admin');
 
         $kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) {
             $this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR'));
             $this->assertSame('10.0.0.2', $request->getClientIp());
             $this->assertSame('foo.bar', $request->getHttpHost());
             $this->assertSame('https', $request->getScheme());
+            $this->assertSame('/admin', $request->getBaseUrl());
         });
 
         SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MAIN_REQUEST, true);

programming_language: PHP