vLLM is an inference and serving engine for large language models (LLMs). The SSRF protection fix for CVE-2026-24779 add in 0.15.1 can be bypassed in the load_from_url_async method due to inconsistent URL parsing behavior between the validation layer and the actual HTTP client. The SSRF fix uses urllib3.util.parse_url() to validate and extract the hostname from user-provided URLs. However, load_from_url_async uses aiohttp for making the actual HTTP requests, and aiohttp internally uses the yarl library for URL parsing. This vulnerability in 0.17.0.
SSRF Protection Bypass in vLLM
Problem type
Affected products
vllm-project
>= 0.15.1, < 0.17.0 - AFFECTED
References
https://github.com/vllm-project/vllm/security/advisories/GHSA-v359-jj2v-j536
https://github.com/vllm-project/vllm/security/advisories/GHSA-qh4c-xf7m-gxfc
https://github.com/vllm-project/vllm/pull/34743
https://github.com/vllm-project/vllm/commit/6f3b2047abd4a748e3db4a68543f8221358002c0
GitHub Security Advisories
GHSA-v359-jj2v-j536
vLLM has SSRF Protection Bypass
https://github.com/advisories/GHSA-v359-jj2v-j536Summary
The SSRF protection fix for https://github.com/vllm-project/vllm/security/advisories/GHSA-qh4c-xf7m-gxfc can be bypassed in the load_from_url_async method due to inconsistent URL parsing behavior between the validation layer and the actual HTTP client.
Affected Component
- File:
vllm/connections.py - Function:
load_from_url_async
Vulnerability Details
Root Cause
The SSRF fix uses urllib3.util.parse_url() to validate and extract the hostname from user-provided URLs. However, load_from_url_async uses aiohttp for making the actual HTTP requests, and aiohttp internally uses the yarl library for URL parsing.
These two URL parsers handle backslash characters (\) differently:
urllib3.parse_url()
https://httpbin.org\@evil.com/
httpbin.org
/%5C@evil.com/
URL-encodes \ as %5C, treats \@evil.com/ as part of the path
yarl (via aiohttp)
https://httpbin.org\@evil.com/
evil.com
/
Treats \ as part of userinfo (user: httpbin.org\), the @ acts as the userinfo/host separator
Attack Scenario
# Attacker provides this URL
malicious_url = "https://httpbin.org\\@evil.com/"
# 1. Validation layer (urllib3.parse_url)
parsed = urllib3.util.parse_url(malicious_url)
# parsed.host == "httpbin.org" ✅ Passes validation
# 2. Actual request (aiohttp with yarl)
async with aiohttp.ClientSession() as session:
async with session.get(malicious_url) as response:
# Request actually goes to evil.com! ❌ Bypass!
Why This Happens
- yarl: Interprets
httpbin.org\as the userinfo component, and@as the userinfo/host separator, so the URL is parsed asuser=httpbin.org\,host=evil.com,path=/ - urllib3: URL-encodes the backslash as
%5C, so\@evil.com/becomes/%5C@evil.com/which is treated as part of the path, leavinghost=httpbin.org
This inconsistency allows an attacker to:
- Bypass the hostname allowlist check
- Access arbitrary internal/external services
- Perform full SSRF attacks
Fixes
https://github.com/vllm-project/vllm/security/advisories/GHSA-qh4c-xf7m-gxfc
https://github.com/vllm-project/vllm/security/advisories/GHSA-v359-jj2v-j536
https://github.com/vllm-project/vllm/pull/34743
https://github.com/vllm-project/vllm/commit/6f3b2047abd4a748e3db4a68543f8221358002c0
https://github.com/advisories/GHSA-v359-jj2v-j536
JSON source
https://cveawg.mitre.org/api/cve/CVE-2026-25960Click to expand
{
"dataType": "CVE_RECORD",
"dataVersion": "5.2",
"cveMetadata": {
"cveId": "CVE-2026-25960",
"assignerOrgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"assignerShortName": "GitHub_M",
"dateUpdated": "2026-03-09T21:01:01.827Z",
"dateReserved": "2026-02-09T17:13:54.066Z",
"datePublished": "2026-03-09T21:01:01.827Z",
"state": "PUBLISHED"
},
"containers": {
"cna": {
"providerMetadata": {
"orgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"shortName": "GitHub_M",
"dateUpdated": "2026-03-09T21:01:01.827Z"
},
"title": "SSRF Protection Bypass in vLLM",
"descriptions": [
{
"lang": "en",
"value": "vLLM is an inference and serving engine for large language models (LLMs). The SSRF protection fix for CVE-2026-24779 add in 0.15.1 can be bypassed in the load_from_url_async method due to inconsistent URL parsing behavior between the validation layer and the actual HTTP client. The SSRF fix uses urllib3.util.parse_url() to validate and extract the hostname from user-provided URLs. However, load_from_url_async uses aiohttp for making the actual HTTP requests, and aiohttp internally uses the yarl library for URL parsing. This vulnerability in 0.17.0."
}
],
"affected": [
{
"vendor": "vllm-project",
"product": "vllm",
"versions": [
{
"version": ">= 0.15.1, < 0.17.0",
"status": "affected"
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"lang": "en",
"description": "CWE-918: Server-Side Request Forgery (SSRF)",
"cweId": "CWE-918",
"type": "CWE"
}
]
}
],
"references": [
{
"url": "https://github.com/vllm-project/vllm/security/advisories/GHSA-v359-jj2v-j536",
"name": "https://github.com/vllm-project/vllm/security/advisories/GHSA-v359-jj2v-j536",
"tags": [
"x_refsource_CONFIRM"
]
},
{
"url": "https://github.com/vllm-project/vllm/security/advisories/GHSA-qh4c-xf7m-gxfc",
"name": "https://github.com/vllm-project/vllm/security/advisories/GHSA-qh4c-xf7m-gxfc",
"tags": [
"x_refsource_MISC"
]
},
{
"url": "https://github.com/vllm-project/vllm/pull/34743",
"name": "https://github.com/vllm-project/vllm/pull/34743",
"tags": [
"x_refsource_MISC"
]
},
{
"url": "https://github.com/vllm-project/vllm/commit/6f3b2047abd4a748e3db4a68543f8221358002c0",
"name": "https://github.com/vllm-project/vllm/commit/6f3b2047abd4a748e3db4a68543f8221358002c0",
"tags": [
"x_refsource_MISC"
]
}
],
"metrics": [
{
"cvssV3_1": {
"version": "3.1",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:L",
"attackVector": "NETWORK",
"attackComplexity": "LOW",
"privilegesRequired": "LOW",
"userInteraction": "NONE",
"scope": "UNCHANGED",
"confidentialityImpact": "HIGH",
"integrityImpact": "NONE",
"availabilityImpact": "LOW",
"baseScore": 7.1,
"baseSeverity": "HIGH"
}
}
]
}
}
}