Starlette is a lightweight ASGI framework/toolkit. Prior to 1.3.0, the HTTP request path is not validated before being used to reconstruct request.url. Because request.url is rebuilt by concatenating {scheme}://{host}{path} and re-parsing the result, a path that does not begin with / (for example @google.com) moves the authority boundary during re-parsing, so request.url.hostname and request.url.netloc become attacker-controlled. Code that reads request.url.hostname (rather than the Host header or scope) can therefore be misled into trusting an attacker-supplied host. This vulnerability is fixed in 1.3.0.
Starlette: Unvalidated request path concatenated into authority poisons request.url.hostname
Problem type
Affected products
Kludex
< 1.3.0 - AFFECTED
References
GitHub Security Advisories
GHSA-jp82-jpqv-5vv3
Starlette: Unvalidated request path concatenated into authority poisons request.url.hostname
https://github.com/advisories/GHSA-jp82-jpqv-5vv3Summary
In affected versions, the HTTP request path is not validated before being used to reconstruct request.url. Because request.url is rebuilt by concatenating {scheme}://{host}{path} and re-parsing the result, a path that does not begin with / (for example @google.com) moves the authority boundary during re-parsing, so request.url.hostname and request.url.netloc become attacker-controlled. Code that reads request.url.hostname (rather than the Host header or scope) can therefore be misled into trusting an attacker-supplied host.
Details
When a client requests a path that does not start with /:
GET @google.com HTTP/1.1
Host: localhost
affected versions reconstruct the URL as http://localhost@google.com. Per RFC 3986 §3.2.1, the substring before @ in the authority is userinfo, so re-parsing yields username = "localhost" and hostname = "google.com", with an empty path:
request.url == "http://localhost@google.com"
request.url.hostname == "google.com"
request.url.path == ""
The root cause is that the path is concatenated directly after the host without a separating /, and without validating that it begins with one. Only the Host header was validated when constructing request.url; the path was not.
This requires an ASGI server that forwards a request-target lacking a leading / into scope["path"].
Impact
Any application running an affected version that uses request.url, request.url.netloc, or request.url.hostname for a security-sensitive decision (host-based authorization, redirect/callback base, SSRF target, cache key, audit log) may be affected, when no fronting proxy or load balancer rejects the malformed request-target first.
Note that this is less exploitable than GHSA-86qp-5c8j-p5mr: there, the poison is carried in the Host header, so the real path still routes to a valid endpoint while request.url.path lies. Here, the poison must be carried in the path itself, and that path (@google.com) does not match any registered route, so routing returns 404 and no endpoint handler runs. The exposure is limited to code that reads request.url before routing - notably middleware - or in 404/exception handlers.
Mitigation
Upgrade to a patched version, which prevents the request path from crossing into the URL authority. The request above instead yields http://localhost/@google.com with request.url.hostname == "localhost".
JSON source
https://cveawg.mitre.org/api/cve/CVE-2026-54282Click to expand
{
"dataType": "CVE_RECORD",
"dataVersion": "5.2",
"cveMetadata": {
"cveId": "CVE-2026-54282",
"assignerOrgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"assignerShortName": "GitHub_M",
"dateUpdated": "2026-06-22T17:26:58.637Z",
"dateReserved": "2026-06-12T17:46:37.292Z",
"datePublished": "2026-06-22T16:45:01.629Z",
"state": "PUBLISHED"
},
"containers": {
"cna": {
"providerMetadata": {
"orgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"shortName": "GitHub_M",
"dateUpdated": "2026-06-22T16:45:01.629Z"
},
"title": "Starlette: Unvalidated request path concatenated into authority poisons request.url.hostname",
"descriptions": [
{
"lang": "en",
"value": "Starlette is a lightweight ASGI framework/toolkit. Prior to 1.3.0, the HTTP request path is not validated before being used to reconstruct request.url. Because request.url is rebuilt by concatenating {scheme}://{host}{path} and re-parsing the result, a path that does not begin with / (for example @google.com) moves the authority boundary during re-parsing, so request.url.hostname and request.url.netloc become attacker-controlled. Code that reads request.url.hostname (rather than the Host header or scope) can therefore be misled into trusting an attacker-supplied host. This vulnerability is fixed in 1.3.0."
}
],
"affected": [
{
"vendor": "Kludex",
"product": "starlette",
"versions": [
{
"version": "< 1.3.0",
"status": "affected"
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"lang": "en",
"description": "CWE-706: Use of Incorrectly-Resolved Name or Reference",
"cweId": "CWE-706",
"type": "CWE"
}
]
}
],
"references": [
{
"url": "https://github.com/Kludex/starlette/security/advisories/GHSA-jp82-jpqv-5vv3",
"name": "https://github.com/Kludex/starlette/security/advisories/GHSA-jp82-jpqv-5vv3",
"tags": [
"x_refsource_CONFIRM"
]
}
],
"metrics": [
{
"cvssV3_1": {
"version": "3.1",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N",
"attackVector": "NETWORK",
"attackComplexity": "HIGH",
"privilegesRequired": "NONE",
"userInteraction": "NONE",
"scope": "UNCHANGED",
"confidentialityImpact": "NONE",
"integrityImpact": "LOW",
"availabilityImpact": "NONE",
"baseScore": 3.7,
"baseSeverity": "LOW"
}
}
]
},
"adp": [
{
"providerMetadata": {
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP",
"dateUpdated": "2026-06-22T17:26:58.637Z"
},
"title": "CISA ADP Vulnrichment",
"metrics": [
{}
]
}
]
}
}