Update dependency guzzlehttp/guzzle to v7.15.1 [SECURITY]#43
Open
renovate[bot] wants to merge 1 commit into
Open
Update dependency guzzlehttp/guzzle to v7.15.1 [SECURITY]#43renovate[bot] wants to merge 1 commit into
renovate[bot] wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
7.12.3→7.15.1Guzzle: Proxy-Authorization headers can be sent to origin servers
GHSA-94pj-82f3-465w
More information
Details
Impact
In affected versions, the built-in cURL handlers (
CurlHandlerandCurlMultiHandler) put every first-class request header in cURL's origin header list (CURLOPT_HTTPHEADER). These handlers are the default when the PHP cURL extension is available. They moveProxy-Authorizationto the proxy-only list (CURLOPT_PROXYHEADER) only when Guzzle predicts an HTTP or HTTPS proxy. A "first-class" header is part of the normal request message and can be set on a PSR-7 request, through clientheadersdefaults, theheadersrequest option, or middleware. It does not include a literal line supplied through rawCURLOPT_HTTPHEADER,CURLOPT_PROXYHEADER, orstream_context.http.headercontrols.Because that migration follows Guzzle's prediction rather than the route libcurl actually takes, the credential stays in the origin list and is sent to the origin server when a request is:
proxyset to''to disable proxying.no,no_proxy, orNO_PROXYmatch.AuthorizationandCookie, does not stripProxy-Authorizationcross-origin.On installations whose libcurl is older than 7.37.0, or whose PHP cURL extension lacks
CURLOPT_PROXYHEADER,CURLOPT_HEADEROPT, andCURLHEADER_SEPARATE, no proxy-only channel is available, so cURL left the header in the origin list for every route. The stream handler also serialized first-class values before selecting a proxy. PHP removes only the firstProxy-Authorizationline from CONNECT, so another first-class value or a URL-userinfo Basic line could reach the tunneled origin. A later rawstream_context.http.proxyoverride could instead reroute either credential directly to the origin.The disclosed value is a private credential meant only for the proxy. RFC 9110 defines
Proxy-Authorizationas credentials for the next inbound proxy, and an origin is never an intended recipient. The flaw can silently give a working proxy credential to an unrelated third party. In the worst case, an attacker controls the origin and records the credential through access logs, tracing systems, or application logs. If it remains valid, the attacker can abuse a paid or access-controlled proxy, impersonate the proxy principal, or reach destinations the proxy is trusted to reach. A strong remote exploit is possible when an application sends a request to an attacker-controlled HTTP URL through a proxy with a defaultProxy-Authorizationheader, then follows the attacker's redirect to an HTTPS or no-proxy destination that Guzzle reaches directly.Using a first-class
Proxy-Authorizationheader is a legitimate, documented configuration, so affected applications are not misusing the library. Guzzle does not create this field, so applications that never configure one are unaffected by the first-class-header flaw. Proxy URL userinfo is not affected on its own, but the stream handler could expose its Basic line when combined with a first-class field or a later rawstream_context.http.proxyoverride.CURLOPT_PROXYUSERPWDis unaffected. Literal lines supplied through rawCURLOPT_HTTPHEADER,CURLOPT_PROXYHEADER, orstream_context.http.headerremain caller-controlled and outside the first-class-header guarantee.Patches
The issue is fixed in
7.14.2. The cURL handlers keep first-classProxy-Authorizationvalues out of the origin header list. When proxy header separation is available, they pass the values throughCURLOPT_PROXYHEADERwithCURLHEADER_SEPARATE. An empty value uses cURL's semicolon form to suppress credentials from proxy URL userinfo. On older builds, Guzzle drops the field for direct, bypassed, and SOCKS routes, but fails before network I/O if the request might use an HTTP or HTTPS proxy.The stream handler removes the field from origin headers before choosing a route. If it selects a proxy, it accepts one value, including empty, writes a validated proxy header, and gives that value precedence over proxy URL userinfo. Multiple values, line breaks, and raw proxy overrides that could reroute generated credentials fail before connection. Direct and bypassed requests drop the field. Versions before
7.14.2are affected by these origin-bound credential paths.Workarounds
If you cannot upgrade immediately, remove first-class
Proxy-Authorizationfields from requests, client defaults, and middleware. Supply proxy credentials instead through proxy URL userinfo, for examplehttp://user:pass@proxy.example:8080, or useCURLOPT_PROXYUSERPWDwith the cURL handlers. Do not combine proxy URL userinfo with a first-class field or a rawstream_context.http.proxyoverride. If a first-class field is unavoidable, use libcurl 7.37.0 or newer withCURLOPT_PROXYHEADER,CURLOPT_HEADEROPT, andCURLHEADER_SEPARATE, and ensure the field is never present on a client that can issue direct, bypassed, or SOCKS requests or follow redirects into those routes. A newer libcurl is necessary but does not fix Guzzle's route-dependent migration by itself, and disabling redirects reduces but does not eliminate exposure.References
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Guzzle: Host-only cookie scope is not preserved
GHSA-wm3w-8rrp-j577
More information
Details
Impact
In affected versions,
CookieJardoes not preserve whether a response cookie was set without aDomainattribute or with an empty one. A cookie withoutDomainis host-only and must be returned only to the exact host that set it. Under current cookie processing rules, an emptyDomainvalue is also host-only. Guzzle instead stores the request host in the cookie'sDomainfield and later applies ordinary domain matching, as though the server had supplied a valid domain. For example, a host-onlysid=secretcookie set byexample.comcan subsequently be sent tochild.example.com.FileCookieJarandSessionCookieJaralso persist the request host without recording the host-only state, so reloading a jar preserves the widened scope.An attacker who controls or can observe a child host can therefore receive cookies that were intended only for its parent host. Depending on the cookie, this can disclose session identifiers, authorization tokens, or other sensitive state. Exploitation requires the application to enable Guzzle's cookie support, reuse the same built-in cookie jar, receive a host-only cookie from a parent host, and later make a matching request to a less-trusted child host. The cookie's other restrictions still apply. Its path must match, a
Securecookie is sent only over a secure connection, and an expired cookie is not sent.Applications that do not use Guzzle's cookie support are not affected. Applications are also not affected by this disclosure if they use a separate jar for every host or trust boundary, never request a less-trusted subdomain with the same jar, or only store cookies carrying a valid, non-empty
Domainattribute. The incorrect behavior occurs between an otherwise valid parent host and its subdomains.Patches
The issue is patched in
7.15.1and later. Starting in that release, Guzzle records whether a response cookie is host-only and matches it only against the exact host. The host-only flag is part of cookie identity for replacement and response-driven deletion. Cookies carrying a valid, non-emptyDomainattribute retain their existing domain-matching behavior. A host-only cookie can coexist with an explicit-domain cookie having the same name, domain string, and path.The built-in persistent jars now write a boolean
HostOnlymarker for every stored cookie record. They reject records where that marker is missing or is not a boolean, and validate all records before changing the live jar. Persisted cookie records written by an older version are therefore rejected rather than silently interpreted with an unsafe scope. Loading non-empty file or session data written without this marker throws aRuntimeExceptionuntil the data is deleted, regenerated, or correctly annotated. Versions before7.15.1are affected.Workarounds
If you cannot upgrade immediately, do not reuse one
CookieJarinstance across parent and child hosts with different trust levels. Use a separate cookie jar for each host or trust boundary, disable cookie handling for requests to less-trusted hosts, or avoid making those requests through a client configured with a shared jar. In particular, avoidnew Client(['cookies' => true])for a client that may contact both a trusted parent host and less-trusted subdomains, because that option creates one jar for the whole client.When upgrading, delete or rotate existing
FileCookieJarandSessionCookieJardata that contains cookie records written without aHostOnlymarker. Records may instead be annotated manually only when the original presence or absence of the cookie'sDomainattribute is known. The stored domain string is not sufficient to infer it safely.References
Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Guzzle: Unbounded response cookies risk denial of service
GHSA-f283-ghqc-fg79
More information
Details
Impact
In affected versions, Guzzle's built-in
CookieJaraccepts any number ofSet-Cookieheader fields from one response, with no limit on the size of each field. When a later request matches the stored cookies, Guzzle places every match into one generatedCookieheader without limiting the number of cookies or the total header length.A malicious or compromised server can therefore return many large cookies, causing Guzzle to store attacker-controlled data in memory and copy it into later request headers. This can increase memory use and processing time. It can also make later requests fail when the generated header exceeds a limit in a handler, HTTP implementation, proxy, or destination server. A server on one sibling host, such as
attacker.example.com, can also set parent-domain cookies that are later selected for another sibling, such asservice.example.com. The denial can therefore affect a different service that uses the same jar.An application is affected when it enables the built-in cookie support, receives an attacker-controlled response, and retains or reuses the jar. The issue affects both built-in handlers because Guzzle manages these cookies itself instead of using libcurl's native cookie engine. cURL addressed a similar denial-of-service issue in CVE-2022-32205 by limiting the cookies it accepts and sends, but those native limits do not protect Guzzle's separate jar. Applications that do not use cookies, use separate jars for untrusted origins, or use a third-party
CookieJarInterfacewith suitable limits are not affected by this behavior. The demonstrated direct impact is limited to availability. The patch does not impose a lifetime limit on a jar built up over an unlimited number of responses or populated directly by application code.Patches
The issue is patched in
7.15.1and later. Starting in that release, the built-inCookieJarignores aSet-Cookiefield value longer than 8,190 bytes and applies at most 50 successful cookie insertions or replacements from one response. When generating a request, it emits at most 150 matchingname=valuepairs and limits the completeCookie:header line to 8,190 bytes, including the field name and following space.These limits follow the same practical shape as cURL's response to CVE-2022-32205. Both bound cookies accepted from one response, cookies added to one request, and generated header size. Guzzle's 8,190-byte incoming field limit is more generous than cURL's current 5,000-byte cookie-line limit. Neither approach adds a global jar quota or an eviction policy. The 8,190-byte incoming boundary is inclusive. Invalid, unrelated, identical, oversized, and deletion fields do not consume the 50-cookie limit. For outgoing requests, Guzzle preserves its existing matching and iteration order. It stops after 150 pairs or before the first matching cookie that would exceed the line limit. The output limits also apply to directly imported cookie state, but that state is not limited when it is added to the jar. Explicit caller-supplied
Cookieheaders and third-party jar implementations remain the caller's responsibility. Versions before7.15.1are affected.Workarounds
If you cannot upgrade immediately, do not enable a shared built-in cookie jar for requests to untrusted origins. Use separate jars per host or trust boundary, disable cookie handling for untrusted requests, and discard or clear a jar after receiving an untrusted response before it is reused. Applications that must accept cookies from untrusted peers can provide a custom
CookieJarInterfaceimplementation that enforces suitable limits.Guzzle does not use libcurl's cookie engine for cookies stored in a
CookieJar. The cURL handler sends theCookieheader that Guzzle's cookie middleware has already built, so libcurl's cookie limits do not apply. Upgrading libcurl therefore does not fix this issue.References
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:LReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Guzzle: URI fragments disclosed in redirect Referer headers
GHSA-h95v-h523-3mw8
More information
Details
Impact
When the optional
refererredirect setting is enabled, affected versions ofRedirectMiddlewarecan copy the fragment from the referring request URI into a generatedRefererheader. A URI fragment is the part after#. It is handled locally by the client and is not part of the HTTP request target, so the server handling the original request does not receive it. A generatedReferertells the redirect destination which URI led to the request. Guzzle correctly removes user information from that value, but retains the fragment when it follows a redirect to the same scheme, such as HTTPS to HTTPS. For example, an initial URI ending in#secretis sent without the fragment, but the redirect destination can receive aRefererending in#secret. This behavior affects both the cURL and stream handlers.An attacker who controls the redirect destination can read the fragment from the incoming header, including through request logs or application code. If the fragment contains a one-time login secret, access token, state value, or other private client data, it is disclosed to a server that was never meant to receive it. Exploitation requires the application to enable
allow_redirects.referer, make a request to a URI with a sensitive fragment, and follow a same-scheme redirect to a less-trusted destination.The
referersetting is disabled by default. Applications that leave it disabled, do not put sensitive data in URI fragments, do not follow redirects, or only redirect within the same trust boundary are not affected. Guzzle already omits the generated header when the scheme changes. This issue is limited to the fragment's inclusion. Reducing the path and query on cross-origin redirects is a separate privacy policy question.Patches
The issue is patched in
7.15.1and later. Starting in that release, Guzzle removes both user information and the fragment before generating a redirectReferervalue. Other redirect behavior does not change. Guzzle retains the referring path and query, and continues to omit the header when the scheme changes. Versions before7.15.1are affected when the optionalreferersetting is enabled.Workarounds
If you cannot upgrade immediately, leave automatic Referer generation disabled. It is off by default. If redirect options are configured explicitly, ensure that
refererisfalse:Alternatively, disable automatic redirects and follow trusted destinations manually, or remove the fragment from the request URI before sending a request that may redirect. Do not rely on the fact that fragments are absent from the initial HTTP request target, because the affected middleware can reintroduce them in the generated header.
References
Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Release Notes
guzzle/guzzle (guzzlehttp/guzzle)
v7.15.1Compare Source
Security
Cookieheaders (GHSA-f283-ghqc-fg79)Refererheaders generated for redirects (GHSA-h95v-h523-3mw8)v7.15.0Compare Source
Added
Multiplexing::NONEsupport as a client, cURL multi handler, and conditional request optionChanged
guzzlehttp/psr7version constraint to^2.13Content-LengthCURLOPT_SHAREcURL option when named connection caps are configuredCURLOPT_PRE_PROXYand opaque share handlesDeprecated
Utils::jsonDecode()andUtils::jsonEncode()in favor of native JSON functionsCURLMOPT_PIPELININGin the cURL multi handleroptionsarrayCURLOPT_PROXYHEADERwithout cURL proxy header separation supportFixed
Content-LengthandTransfer-Encodingwhen redirects discard the request bodydelayrequest option to followed redirectsv7.14.2Compare Source
Security
v7.14.1Compare Source
Changed
guzzlehttp/psr7version constraint to^2.12.5Fixed
@separatorsstream => true) on cap-configured stream handlersoptionsvaluesCURLOPT_HTTPAUTHmask permits NTLMCURLMOPT_PIPELININGwhen combined with explicit multiplexingon_statscallback throwson_trailerscallback is configuredon_trailerscallback before starting a cURL transferon_trailersrequest option on the stream handler, which cannot observe trailersv7.14.0Compare Source
Added
on_trailersrequest option to expose parsed HTTP response trailersmultiplexrequest option withMultiplexing::*modes to control or require HTTP/2 multiplexingmultiplexrequests whenCURLMOPT_PIPELININGdisables multiplexingmax_host_connectionsandmax_total_connectionsclient and cURL multi handler optionsChanged
CURLOPT_SHAREwhen combined with authenticated SOCKS proxy configurationCURLOPT_CERTINFOoptionDeprecated
CURLOPT_PIPEWAITcURL option in favour of themultiplexrequest optionselect_timeoutcURL multi handler option valuesv7.13.3Compare Source
Changed
guzzlehttp/promisesversion constraint to^2.5.1guzzlehttp/psr7version constraint to^2.12.4Fixed
no_proxyvaluesv7.13.2Compare Source
Fixed
RuntimeExceptionv7.13.1Compare Source
Fixed
v7.13.0Compare Source
Added
crypto_method_maxrequest option to cap the maximum TLS protocol versionChanged
CURLOPT_SHAREwhen combined with authenticated HTTP/HTTPS proxy tunnel configurationCURLOPT_PREREQFUNCTIONcallbacks when defined by PHP cURLcrypto_methodrequests to the stream handler when cURL cannot select TLS 1.2Deprecated
Configuration
📅 Schedule: (UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.