Jul 21, 2026·6 min read·12 visits
Guzzle HTTP client leaks client-side URI fragments containing sensitive data (like access tokens) in Referer headers when auto-redirects are configured with referer tracking enabled.
An issue in Guzzle's RedirectMiddleware allows client-side URI fragments to be leaked over the network in Referer headers during same-scheme HTTP redirects.
The vulnerability resides within the Guzzle HTTP client's redirect handling component, specifically GuzzleHttp\Psr7 and the GuzzleHttp\Middleware\RedirectMiddleware class. Guzzle is a highly popular PHP HTTP client widely used in modern web applications to coordinate integrations and third-party API interactions. Under certain circumstances, configurations that automate redirect processing can expose sensitive client-side data over the network.\n\nWhen a developer explicitly configures the Guzzle client to automatically generate and forward the Referer header during HTTP redirects, the underlying middleware attempts to reconstruct the request's origin context. However, versions of the Guzzle library prior to 7.15.1 fail to validate the structure of the origin URI, enabling client-side fragment data to be serialized and processed over the network. This behavior directly expands the attack surface to include third-party services that receive these redirected request headers.\n\nThe vulnerability class corresponds to CWE-201 (Insertion of Sensitive Information Into Sent Data), stemming from an incorrect abstraction of URI boundaries. Standard web specifications indicate that URI fragments must never traverse the network. By violating this protocol, Guzzle transmits client-side processing states, such as OAuth tokens or single-sign-on hashes, directly to unauthorized network end-points during same-scheme redirections.
To understand the technical root cause, we must evaluate the distinction between a URI's query parameters and its fragment components. According to RFC 3986 Section 3.5, the fragment identifier contains client-side instructions that identify a secondary resource. Traditional user agents, such as modern web browsers, separate the fragment component from the target URI before executing any HTTP request over the network. Guzzle, as a programmatic HTTP client, implements PSR-7 standards where the entire URI is held in memory as an instance of UriInterface.\n\nWhen Guzzle's RedirectMiddleware intercepts an HTTP 3xx redirect response, it checks if same-scheme redirection is occurring (for instance, redirecting from one HTTPS endpoint to another HTTPS endpoint). If the 'allow_redirects' configuration has 'referer' tracking enabled, Guzzle programmatically builds a new Referer header. It extracts the original request's URI object and attempts to clean it before adding it to the headers array.\n\nThe structural failure in Guzzle's sanitization process is that it only strips the user credentials (username and password) via the withUserInfo('') method. The middleware does not attempt to purge the fragment component. Consequently, the original URI is cast directly to a string, causing Guzzle to serialize the client-side fragment and send it to the destination server in the Referer header.
Analyzing the source code of Guzzle's RedirectMiddleware.php reveals the precise implementation bug. In vulnerable versions, the middleware validates that same-scheme redirects are occurring prior to constructing the Referer header, but it lacks any logical checks to purge the fragment data.\n\nBelow is the code comparison between the vulnerable and patched implementations of the modifyRequest function within Guzzle's RedirectMiddleware class:\n\nphp\\n// Vulnerable Implementation (Guzzle < 7.15.1)\\nif ($options['allow_redirects']['referer']\\n && $modify['uri']->getScheme() === $request->getUri()->getScheme()\\n) {\\n // Only user info is stripped; the URI fragment is retained\\n $uri = $request->getUri()->withUserInfo('');\\n $modify['set_headers']['Referer'] = (string) $uri;\\n} else {\\n $modify['remove_headers'][] = 'Referer';\\n}\\n\\n// Patched Implementation (Guzzle >= 7.15.1)\\nif ($options['allow_redirects']['referer']\\n && $modify['uri']->getScheme() === $request->getUri()->getScheme()\\n) {\\n // Both user info and fragment are explicitly stripped\\n $uri = $request->getUri()->withUserInfo('')->withFragment('');\\n $modify['set_headers']['Referer'] = (string) $uri;\\n} else {\\n $modify['remove_headers'][] = 'Referer';\\n}\\n\n\nThe patch resolves this by appending the withFragment('') call to the method chain. This returns a cloned UriInterface instance with the fragment property set to an empty string. However, security researchers should observe that query parameters are not stripped. If Guzzle initiates a redirect to a cross-origin server, any sensitive data held in query parameters (such as ?api_key=SECRET) will still be transmitted because Guzzle only validates that the redirect target's scheme matches the source scheme, leaving further domain validation to the developer.
An attacker seeking to exploit this vulnerability must target an application that communicates with a service that handles secrets inside URI fragments, such as an OAuth 2.0 authorization server using the implicit grant flow. The client must also have Guzzle's referer-tracking redirect behavior explicitly configured. The attacker must control the destination of a redirect, either via an open redirect flaw on the trusted host or by directly manipulating the client to follow a link to an attacker-controlled server.\n\nWhen the Guzzle client issues a request containing a fragment and the trusted endpoint responds with a 302 Redirect to the attacker's server, Guzzle automatically generates the Referer header. It retains the fragment in the Referer header, sending it to the attacker's host. The attacker then parses their server's access logs to extract the secret.\n\nmermaid\\ngraph LR\\n Client[\"Guzzle Client\\n'allow_redirects.referer' => true\"] -->|\"1. GET /callback#token=SECRET\"| Trusted[\"Trusted Host\\n(trusted-api.com)\"]\\n Trusted -->|\"2. 302 Redirect\\nLocation: https://evil.com/logger\"| Client\\n Client -->|\"3. GET /logger\\nReferer: https://trusted-api.com/callback#token=SECRET\"| Attacker[\"Attacker Server\\n(evil.com)\"]\\n\n\nNo weaponized exploit tools are currently documented in the wild. However, test assertions in Guzzle's test suite confirm that the fragment is transmitted when this code path is traversed under vulnerable configurations.
The impact of this vulnerability is a high-risk disclosure of confidential secrets. If an application utilizes fragments to pass temporary authorization keys, single-sign-on parameters, or OAuth state tokens, these values are immediately exposed to any external host that receives a redirect from the client.\n\nAn attacker obtaining these tokens can perform session hijacking, impersonate the application user, or access private application-programming interfaces. The vulnerability has a CVSS v3.1 base score of 5.9, reflecting a high confidentiality impact, with low complexity and no privileges required, balanced by the configuration prerequisites.\n\nBecause this vulnerability has no assigned CVE ID, it is not listed in the CISA KEV catalog, and EPSS scores are not calculated. Nevertheless, the lack of a formal CVE does not diminish the potential severity for systems using insecure redirect configurations.
The primary remediation path is upgrading the guzzlehttp/guzzle package to version 7.15.1 or later. The security release replaces the vulnerable code path and guarantees that all URI fragments are stripped prior to Referer header serialization.\n\nIf upgrading the library is not immediately possible, you should verify that Guzzle's referer tracking is disabled. This is Guzzle's default behavior. Ensure that any client instantiations do not explicitly enable this parameter, or explicitly configure it to false as shown below:\n\nphp\\n$client->request('GET', $uri, [\\n 'allow_redirects' => [\\n 'referer' => false, // Explicitly disabled\\n ],\\n]);\\n\n\nDevelopers can also manually sanitize incoming URIs by utilizing PSR-7 methods to strip fragments before executing requests. For example, calling $cleanUri = $uri->withFragment(''); guarantees that the client never processes or forwards client-side data over the network.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
guzzlehttp/guzzle Guzzle | < 7.15.1 | 7.15.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-201 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 5.9 (Medium) |
| Exploit Status | None/Unproven |
| EPSS Score | N/A |
| CISA KEV Status | Not Listed |
| Impact | Information Disclosure |
The product inserts sensitive information into a record or data flow that is sent to another actor.
CVE-2026-12243 is a path traversal vulnerability in the Natural Language Toolkit (NLTK) version 3.9.4. The flaw exists because the input validation routine fails to account for percent-encoded directory traversal sequences like '..%2f' before passing them to urllib.request.url2pathname(), which decodes them into active traversal sequences.
CVE-2026-73654 is a high-severity prototype pollution vulnerability in Trigger.dev. The flaw occurs during the handling of run-metadata updates through the PUT /api/v1/runs/:runId/metadata endpoint. Because user-supplied keys are parsed directly by the @jsonhero/path library without sanitization, an authenticated attacker with low privileges can pollute the global Object.prototype. This causes database queries via Prisma ORM to fail validation and induces unhandled exceptions in the Prometheus metrics client, resulting in a process-wide denial of service.
CVE-2026-73559 is an uncontrolled resource consumption vulnerability in the vLLM engine, specifically within the /v1/completions API endpoint, allowing authenticated attackers to cause application-level denial of service via unbounded prompt arrays.
A critical security bypass vulnerability in Argo Workflows allows authenticated attackers with workflow submission privileges to bypass 'Strict' or 'Secure' template referencing restrictions. By injecting unvalidated fields into the nested ArtifactGC configuration, attackers can execute arbitrary pod patches, leading to host namespace escape and cluster-wide privilege escalation.
A Server-Side Request Forgery (SSRF) / Confused Deputy vulnerability has been identified in Pydantic AI UI Adapters (such as VercelAIAdapter). Under certain conditions, a malicious client can supply manipulated message history with provider metadata that forces the server to resolve files within privileged cloud environments (AWS S3, Google Cloud Storage) or model providers. This occurs because the adapters deserialize client-provided metadata structures directly into UploadedFile instances without validation, which are subsequently fetched using high-privilege server credentials.
A path traversal vulnerability in the optional dashboard server of atomic-agents-stack before version 1.1.0 allows unauthenticated remote attackers to read arbitrary files from the host filesystem.