CVE-2026-69246

Guzzle: Noncanonical host can bypass host-based checks

Published Aug 3, 2026 CVSS 3.1 · 7.2 High EPSS < 1% KEV · Not listed
Description
Guzzle is an extensible PHP HTTP client. Prior to 7.15.2 and 8.0.1, Guzzle gives a transport the request URI as text and supplies the Host header separately. The cURL handlers set CURLOPT_URL to the URI exactly as written and push that Host into CURLOPT_HTTPHEADER; StreamHandler does the same through fopen(). libcurl then parses the authority itself, percent-decoding it and, on an IDN-capable build, applying IDNA mapping, and uses the result to resolve, connect, name the TLS peer and address a proxy CONNECT, while the supplied Host suppresses the aligned one libcurl would have generated. For a URI host written as 127.0.0.%31, filter_var() rejects the host as an IP literal, yet libcurl decodes it to 127.0.0.1 and reaches loopback with no DNS lookup while the server receives Host: 127.0.0.%31. An attacker who influences a fetched URI can therefore reach a host the application's checks excluded and read whatever the host exposes of the response. The same divergence moves Guzzle's own decisions onto a spelling the transport does not use: no_proxy selects proxy routing from the literal host, and RedirectMiddleware decides from it whether to strip Authorization and Cookie. Exploitation requires the application to build a request URI from untrusted input and to make a host decision before handing it to Guzzle. This issue is fixed in versions 7.15.2 and 8.0.1.

Analysis

AI-generated

Technical impact

Guzzle, a widely used PHP HTTP client, implemented a vulnerability in which a noncanonical host component in a request URI could be decoded differently by the underlying transport layer than by the PHP code’s validation. In particular, a URI such as 127.0.0.%31 is rejected by PHP’s filter_var() as an invalid IP literal, but libcurl decodes the percent‐encoded %31 to a decimal 1, resolving the host to 127.0.0.1. The application’s Host header remains 127.0.0.%31, allowing the attacker to reach a loopback address that the application’s own host checks would normally exclude, and read any response from that internal server. Because the transport is driven by the parsed host, the client’s decision logic (proxy selection, no_proxy handling, and redirect middleware that strips authentication headers) is also based on the decoded host, further expanding the attack surface.

Affected Systems

The affected software is the Guzzle PHP HTTP client. Versions prior to 7.15.2 for the 7.x branch and prior to 8.0.1 for the 8.x branch are vulnerable. The fix is implemented in Guzzle 7.15.2 and 8.0.1 and later.

Risk and Exploitability

The CVSS base score is 7.2, indicating a high severity. No EPSS score is available, and the vulnerability is not listed in CISA’s KEV. Exploitation requires the application to build a request URI from untrusted input and to rely on Guzzle’s host decision before the request is sent. Attackers who can supply such input can redirect traffic to internal hosts, potentially exposing sensitive data or enabling further compromise.

Remediation

No solution or workaround provided in the CVE record.

OpenCVE Recommended Actions

  • Update Guzzle to version 7.15.2 or later, or 8.0.1 or later.
  • Perform strict host validation and canonicalization on any user‑supplied URI before invoking Guzzle, ensuring that percent‑encoded hosts resolve to approved addresses and reject loopback values.
  • Apply a domain whitelist or restrict Guzzle to trusted endpoints only; reject any request where the target host is not in the whitelist.

Generated by OpenCVE AI on August 4, 2026 at 20:44 UTC.

Tracking

Sign in to view the affected projects.

Advisories

Source ID Title
Github GHSA Github GHSA GHSA-v5mv-p594-2x33 Guzzle: Noncanonical host can bypass host-based checks
History
Type Values Removed Values Added
First Time appeared Guzzlephp
Guzzlephp guzzle
Vendors & Products Guzzlephp
Guzzlephp guzzle
Type Values Removed Values Added
Metrics ssvc

{'options': {'Automatable': 'yes', 'Exploitation': 'none', 'Technical Impact': 'partial'}, 'version': '2.0.3'}

Type Values Removed Values Added
Description Guzzle is an extensible PHP HTTP client. Prior to 7.15.2 and 8.0.1, Guzzle gives a transport the request URI as text and supplies the Host header separately. The cURL handlers set CURLOPT_URL to the URI exactly as written and push that Host into CURLOPT_HTTPHEADER; StreamHandler does the same through fopen(). libcurl then parses the authority itself, percent-decoding it and, on an IDN-capable build, applying IDNA mapping, and uses the result to resolve, connect, name the TLS peer and address a proxy CONNECT, while the supplied Host suppresses the aligned one libcurl would have generated. For a URI host written as 127.0.0.%31, filter_var() rejects the host as an IP literal, yet libcurl decodes it to 127.0.0.1 and reaches loopback with no DNS lookup while the server receives Host: 127.0.0.%31. An attacker who influences a fetched URI can therefore reach a host the application's checks excluded and read whatever the host exposes of the response. The same divergence moves Guzzle's own decisions onto a spelling the transport does not use: no_proxy selects proxy routing from the literal host, and RedirectMiddleware decides from it whether to strip Authorization and Cookie. Exploitation requires the application to build a request URI from untrusted input and to make a host decision before handing it to Guzzle. This issue is fixed in versions 7.15.2 and 8.0.1.
Title Guzzle: Noncanonical host can bypass host-based checks
Weaknesses CWE-180
CWE-436
CWE-918
CWE-941
References
Metrics cvssV3_1

{'score': 7.2, 'vector': 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N'}

Weaknesses
  • CWE-180

    Incorrect Behavior Order: Validate Before Canonicalize

  • CWE-436

    Interpretation Conflict

  • CWE-918

    Server-Side Request Forgery (SSRF)

  • CWE-941

    Incorrectly Specified Destination in a Communication Channel

Sources

Status
PUBLISHED
Assigner
GitHub_M
Published
Updated
Aug 4, 2026, 2:06 PM
Reserved
Aug 3, 2026, 7:54 PM
Status
Awaiting Analysis
Published
Aug 3, 2026, 9:16 PM
Modified
Sep 8, 2026, 8:41 PM