vLLM SSRF: when the allowlist patch carried the same parser bug
Two vLLM advisories show the same flaw twice: a host allowlist validated with one URL parser and fetched with another. The fix swapped the parser pair and reopened the bypass.
What is this?
vLLM’s multimodal models can fetch images, audio and video from URLs supplied in a request. To stop that feature from becoming a Server-Side Request Forgery (SSRF) primitive, vLLM checks each URL’s host against an allowlist before fetching. Two advisories show that the check has been defeated the same way twice.
The first, CVE-2026-24779 (GHSA-qh4c-xf7m-gxfc, published January 27, 2026, CVSS 7.1 High), is an SSRF in the MediaConnector class: the host is validated with one URL parser and fetched with a different one. The second, CVE-2026-25960 (GHSA-v359-jj2v-j536, published March 9, 2026, CVSS 5.4 Moderate), is the bypass of the fix: the patch moved the validation to a new parser, but the async fetch path still used yet another parser. Same class of bug, reopened by the remediation. Both are CWE-918, and the chain is fully patched in vLLM 0.17.0.
How it works
The pattern is a parser differential: validate the URL with parser A, send the request with parser B, and rely on the two agreeing on which host you are talking to. When they disagree, the allowlist guards a hostname that the HTTP client never actually contacts.
In the original MediaConnector finding, validation used Python’s urllib (urlparse) while the fetch used requests (backed by urllib3). The two follow different URL grammars — one closer to RFC 3986, the other to the WHATWG URL standard — and they disagree on how a backslash is handled, which is enough to slip a different host past the allowlist.
The fix (PR #32746) standardised validation on urllib3.util.parse_url(). But the asynchronous fetch path, load_from_url_async in vllm/connections.py, sends the request with aiohttp, which parses URLs using the yarl library. The advisory documents the disagreement precisely:
Input URL: https://httpbin.org\@evil.com/
urllib3.parse_url() -> host = httpbin.org (encodes "\" as %5C, treats "\@evil.com/" as path)
yarl (via aiohttp) -> host = evil.com (treats "httpbin.org\" as userinfo, "@" as separator)
So the validator sees httpbin.org and approves the request; aiohttp then connects to evil.com. The allowlist passes, the fetch goes somewhere else. No exotic payload is needed — the canonical example URL is in the public advisory, and the underlying technique (backslash and @/userinfo confusion between URL parsers) is a long-known SSRF filter-bypass class, not a new attack.
Why it matters
SSRF on an inference server is more than an outbound curl. vLLM is frequently deployed inside clusters — the advisory calls out llm-d-style topologies — where a pod sits on a trusted internal network with no egress filtering. A request-controlled fetch then lets an attacker reach internal services the pod can see: metadata endpoints, peer pods, management APIs and databases. The first advisory notes an attacker could hit an internal management endpoint and report false metrics (for example, a bogus KV-cache state), destabilising the serving fleet.
The wider lesson is the one the two CVEs make by repetition. Validate-then-fetch is safe only if the same component resolves the host both times. Swapping urllib→urllib3 for urllib3→yarl fixed one specific differential and introduced another, because the architecture — “parse twice, trust they agree” — was left intact. Allowlist bypasses are rarely about a single bad regex; they are about two pieces of code disagreeing on what a string means.
Defenses
If you run vLLM with multimodal URL fetching, upgrade to 0.17.0 or later, which patches the async path (PR #34743).
Beyond patching, treat the URL-fetch feature as the SSRF sink it is. Disable remote media fetching if your deployment does not need it, and feed models pre-fetched bytes instead. Where fetching is required, enforce the boundary at the network layer rather than in string parsing: deny the inference pod egress to internal CIDRs and the cloud metadata IP, so an allowlist bypass reaches nothing useful.
For the parser-differential class specifically, do not validate one representation of a URL and then hand the raw string to a different client. Parse once, resolve the host to an IP, check that IP against your policy, and connect to that pinned address — so the host you approved is the host you contact. Block redirects on media fetches (vLLM gates this behind VLLM_MEDIA_URL_ALLOW_REDIRECTS), since a 30x response is another way to move the real destination after the check.
Status
| Item | Detail |
|---|---|
| CVE-2026-24779 (MediaConnector SSRF) | Published Jan 27, 2026 · CVSS 7.1 High · fix PR #32746 |
| CVE-2026-25960 (SSRF protection bypass) | Published Mar 9, 2026 · CVSS 5.4 Moderate · affects vLLM ≥ 0.15.1 · fix PR #34743 |
| Patched in | vLLM 0.17.0 |
| Weakness | CWE-918 (Server-Side Request Forgery) |
Sources
- → https://github.com/advisories/GHSA-qh4c-xf7m-gxfc
- → https://github.com/vllm-project/vllm/security/advisories/GHSA-v359-jj2v-j536
- → https://github.com/vllm-project/vllm/commit/f46d576c54fb8aeec5fc70560e850bed38ef17d7
- → https://github.com/vllm-project/vllm/pull/32746
- → https://github.com/vllm-project/vllm/pull/34743