CVE-2022-31043 (PHP, published 2022-06-10T00:15Z)
Description: value: 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.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-212 \u2014 Improper Removal of Sensitive Information Before Storage or Transfer
The product stores, transfers, or shares a resource that contains sensitive information, but it does not properly remove that information before the product makes the resource available to unauthorized actors.
Repository: https://github.com/guzzle/guzzle
Files changed:
CHANGELOG.md
src/RedirectMiddleware.php
tests/RedirectMiddlewareTest.php
Commit message: Release 7.4.4 (#3023)



Vulnerable code:
     * Check for too many redirects
        $uri = $this->redirectUri($request, $response, $protocols);
        // Remove Authorization header if host is different.
        if ($request->getUri()->getHost() !== $modify['uri']->getHost()) {
     * Set the appropriate URL on the request based on the location header
    private function redirectUri(RequestInterface $request, ResponseInterface $response, array $protocols): UriInterface
    {
    public function testRemoveAuthorizationHeaderOnRedirect()
            new Response(302, ['Location' => 'http://test.com']),
            static function (RequestInterface $request) {
                self::assertFalse($request->hasHeader('Authorization'));
        $client->get('http://example.com?a=b', ['auth' => ['testuser', 'testpass']]);

Fixed code:
## 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

     * Check for too many redirects.
        $uri = self::redirectUri($request, $response, $protocols);
        // Remove Authorization and Cookie headers if required.
        if (self::shouldStripSensitiveHeaders($request->getUri(), $modify['uri'])) {
            $modify['remove_headers'][] = 'Cookie';
     * 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 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 {
    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)
            new Response(302, ['Location' => $targetUri]),
            static function (RequestInterface $request) use ($shouldBePresent) {
                self::assertSame($shouldBePresent, $request->hasHeader('Authorization'));
                self::assertSame($shouldBePresent, $request->hasHeader('Cookie'));

        $client->get($originalUri, ['auth' => ['testuser', 'testpass'], 'headers' => ['Cookie' => 'foo=bar']]);