VYPR
High severityNVD Advisory· Published Jun 9, 2022· Updated Apr 23, 2025

Fix failure to strip Authorization header on HTTP downgrade in Guzzle

CVE-2022-31043

Description

Guzzle is an open source PHP HTTP client. In affected versions Authorization headers on requests are sensitive information. On making a request using the https scheme to a server which responds with a redirect to a URI with the http scheme, we should not forward the Authorization header on. This is much the same as to how we don't forward on the header if the host changes. Prior to this fix, https to http downgrades did not result in the Authorization header being removed, only changes to the host. Affected Guzzle 7 users should upgrade to Guzzle 7.4.4 as soon as possible. Affected users using any earlier series of Guzzle should upgrade to Guzzle 6.5.7 or 7.4.4. Users unable to upgrade may consider an alternative approach which would be to use their own redirect middleware. Alternately users may simply disable redirects all together if redirects are not expected or required.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Guzzle PHP HTTP client fails to strip Authorization headers during HTTPS-to-HTTP downgrade redirects, leaking credentials.

Vulnerability

CVE-2022-31043 affects the Guzzle PHP HTTP client, an extensible library for sending HTTP requests [3]. In affected versions, when a request is made via HTTPS and the server responds with a redirect to an HTTP URI, the client incorrectly preserves the Authorization header in the redirected request [2]. This behavior violates HTTP semantics, which mandate that sensitive headers like Authorization should not be forwarded when the scheme downgrades from HTTPS to HTTP, similar to how they are not forwarded on host changes [1].

Attack

Vector

Exploitation requires a trusted HTTPS server that can be induced to return a 3xx redirect to an http:// URL. An attacker in a position to intercept or observe network traffic on the unencrypted HTTP channel could then capture the leaked Authorization header. The vulnerability does not require any special privileges beyond normal HTTP interaction with the vulnerable client [2].

Impact

An attacker who obtains the Authorization header can gain unauthorized access to any resources or services protected by that credential, potentially leading to account takeover or privilege escalation. The leak occurs silently, without the user's knowledge, making it a high-severity information disclosure issue [2].

Mitigation

Guzzle 6.5.7 and 7.4.4 fix the issue by correctly removing the Authorization header on scheme downgrades. Users on older versions should upgrade immediately. For those unable to upgrade, alternative mitigations include implementing custom redirect middleware that strips sensitive headers, or disabling redirect support entirely if not needed [2][4].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
guzzlehttp/guzzlePackagist
>= 4.0.0, < 6.5.76.5.7
guzzlehttp/guzzlePackagist
>= 7.0.0, < 7.4.47.4.4

Affected products

3

Patches

1
e3ff079b2282

Release 7.4.4 (#3023)

https://github.com/guzzle/guzzleGraham CampbellJun 9, 2022via ghsa
3 files changed · +63 12
  • CHANGELOG.md+5 0 modified
    @@ -2,6 +2,11 @@
     
     Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version.
     
    +## 7.4.4 - 2022-06-09
    +
    +* Fix failure to strip Authorization header on HTTP downgrade
    +* Fix failure to strip the Cookie header on change in host or HTTP downgrade
    +
     ## 7.4.3 - 2022-05-25
     
     * Fix cross-domain cookie leakage
    
  • src/RedirectMiddleware.php+34 7 modified
    @@ -142,7 +142,7 @@ static function (ResponseInterface $response) use ($uri, $statusCode) {
         }
     
         /**
    -     * Check for too many redirects
    +     * Check for too many redirects.
          *
          * @throws TooManyRedirectsException Too many redirects.
          */
    @@ -178,7 +178,7 @@ public function modifyRequest(RequestInterface $request, array $options, Respons
                 $modify['body'] = '';
             }
     
    -        $uri = $this->redirectUri($request, $response, $protocols);
    +        $uri = self::redirectUri($request, $response, $protocols);
             if (isset($options['idn_conversion']) && ($options['idn_conversion'] !== false)) {
                 $idnOptions = ($options['idn_conversion'] === true) ? \IDNA_DEFAULT : $options['idn_conversion'];
                 $uri = Utils::idnUriConvert($uri, $idnOptions);
    @@ -198,19 +198,46 @@ public function modifyRequest(RequestInterface $request, array $options, Respons
                 $modify['remove_headers'][] = 'Referer';
             }
     
    -        // Remove Authorization header if host is different.
    -        if ($request->getUri()->getHost() !== $modify['uri']->getHost()) {
    +        // Remove Authorization and Cookie headers if required.
    +        if (self::shouldStripSensitiveHeaders($request->getUri(), $modify['uri'])) {
                 $modify['remove_headers'][] = 'Authorization';
    +            $modify['remove_headers'][] = 'Cookie';
             }
     
             return Psr7\Utils::modifyRequest($request, $modify);
         }
     
         /**
    -     * Set the appropriate URL on the request based on the location header
    +     * Determine if we should strip sensitive headers from the request.
    +     *
    +     * We return true if either of the following conditions are true:
    +     *
    +     * 1. the host is different;
    +     * 2. the scheme has changed, and now is non-https.
          */
    -    private function redirectUri(RequestInterface $request, ResponseInterface $response, array $protocols): UriInterface
    -    {
    +    private static function shouldStripSensitiveHeaders(
    +        UriInterface $originalUri,
    +        UriInterface $modifiedUri
    +    ): bool {
    +        if (\strcasecmp($originalUri->getHost(), $modifiedUri->getHost()) !== 0) {
    +            return true;
    +        }
    +
    +        if ($originalUri->getScheme() !== $modifiedUri->getScheme() && 'https' !== $modifiedUri->getScheme()) {
    +            return true;
    +        }
    +
    +        return false;
    +    }
    +
    +    /**
    +     * Set the appropriate URL on the request based on the location header.
    +     */
    +    private static function redirectUri(
    +        RequestInterface $request,
    +        ResponseInterface $response,
    +        array $protocols
    +    ): UriInterface {
             $location = Psr7\UriResolver::resolve(
                 $request->getUri(),
                 new Psr7\Uri($response->getHeaderLine('Location'))
    
  • tests/RedirectMiddlewareTest.php+24 5 modified
    @@ -272,18 +272,37 @@ public function testInvokesOnRedirectForRedirects()
             self::assertTrue($call);
         }
     
    -    public function testRemoveAuthorizationHeaderOnRedirect()
    +    public function crossOriginRedirectProvider()
    +    {
    +        return [
    +            ['http://example.com?a=b', 'http://test.com/', false],
    +            ['https://example.com?a=b', 'https://test.com/', false],
    +            ['http://example.com?a=b', 'https://test.com/', false],
    +            ['https://example.com?a=b', 'http://test.com/', false],
    +            ['http://example.com?a=b', 'http://example.com/', true],
    +            ['https://example.com?a=b', 'https://example.com/', true],
    +            ['http://example.com?a=b', 'https://example.com/', true],
    +            ['https://example.com?a=b', 'http://example.com/', false],
    +        ];
    +    }
    +
    +    /**
    +     * @dataProvider crossOriginRedirectProvider
    +     */
    +    public function testHeadersTreatmentOnRedirect($originalUri, $targetUri, $shouldBePresent)
         {
             $mock = new MockHandler([
    -            new Response(302, ['Location' => 'http://test.com']),
    -            static function (RequestInterface $request) {
    -                self::assertFalse($request->hasHeader('Authorization'));
    +            new Response(302, ['Location' => $targetUri]),
    +            static function (RequestInterface $request) use ($shouldBePresent) {
    +                self::assertSame($shouldBePresent, $request->hasHeader('Authorization'));
    +                self::assertSame($shouldBePresent, $request->hasHeader('Cookie'));
    +
                     return new Response(200);
                 }
             ]);
             $handler = HandlerStack::create($mock);
             $client = new Client(['handler' => $handler]);
    -        $client->get('http://example.com?a=b', ['auth' => ['testuser', 'testpass']]);
    +        $client->get($originalUri, ['auth' => ['testuser', 'testpass'], 'headers' => ['Cookie' => 'foo=bar']]);
         }
     
         public function testNotRemoveAuthorizationHeaderOnRedirect()
    

Vulnerability mechanics

Synthesis attempt was rejected by the grounding validator. Re-run pending.

References

8

News mentions

0

No linked articles in our index yet.