{"id":"CVE-2026-54282","aliases":["GHSA-jp82-jpqv-5vv3","PYSEC-2026-248"],"title":"Starlette: Unvalidated request path concatenated into authority poisons request.url.hostname","summary":"Starlette: Unvalidated request path concatenated into authority poisons request.url.hostname","severity":"low","cvss":3.7,"cvssVector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N","vendor":"starlette","product":"starlette","ecosystem":"pip","affected":["starlette < 1.3.0"],"patched":["starlette 1.3.0"],"published":"2026-06-15","updated":"2026-09-10","sourceUpdated":"2026-09-10T03:50:50.050800090Z","source":"OSV","sourceUrl":"https://osv.dev/vulnerability/GHSA-jp82-jpqv-5vv3","references":[{"url":"https://github.com/Kludex/starlette/security/advisories/GHSA-jp82-jpqv-5vv3"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-54282"},{"url":"https://github.com/Kludex/starlette"},{"url":"https://github.com/pypa/advisory-database/tree/main/vulns/starlette/PYSEC-2026-248.yaml"},{"url":"https://github.com/advisories/GHSA-jp82-jpqv-5vv3"}],"tags":["osv","pip","ghsa"],"epss":0.00187,"epssPercentile":0.08546,"cwe":["CWE-20","CWE-706"],"ingestedAt":"2026-07-07T15:41:58.627Z","slug":"CVE-2026-54282","body":"## Overview\n\n### Summary\n\nIn 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.\n\n### Details\n\nWhen a client requests a path that does not start with `/`:\n\n```http\nGET @google.com HTTP/1.1\nHost: localhost\n```\n\naffected versions reconstruct the URL as `http://localhost@google.com`. Per [RFC 3986 §3.2.1](https://www.rfc-editor.org/rfc/rfc3986.html#section-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:\n\n```text\nrequest.url          == \"http://localhost@google.com\"\nrequest.url.hostname == \"google.com\"\nrequest.url.path     == \"\"\n```\n\nThe 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.\n\nThis requires an ASGI server that forwards a request-target lacking a leading `/` into `scope[\"path\"]`.\n\n### Impact\n\nAny 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.\n\nNote that this is less exploitable than [GHSA-86qp-5c8j-p5mr](https://github.com/Kludex/starlette/security/advisories/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.\n\n### Mitigation\n\nUpgrade 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\"`.\n\n## Affected packages\n\n- `starlette < 1.3.0`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `starlette 1.3.0`","depth":"sunlit","depthScore":20,"depthScoreParts":{"impact":20.4,"likelihood":0,"exploitation":0,"ransomware":0},"changes":[]}