vLLM vulnerable to Server-Side Request Forgery (SSRF) in `MediaConnector`
Description
vLLM is an inference and serving engine for large language models (LLMs). Prior to version 0.14.1, a Server-Side Request Forgery (SSRF) vulnerability exists in the MediaConnector class within the vLLM project's multimodal feature set. The load_from_url and load_from_url_async methods obtain and process media from URLs provided by users, using different Python parsing libraries when restricting the target host. These two parsing libraries have different interpretations of backslashes, which allows the host name restriction to be bypassed. This allows an attacker to coerce the vLLM server into making arbitrary requests to internal network resources. This vulnerability is particularly critical in containerized environments like llm-d, where a compromised vLLM pod could be used to scan the internal network, interact with other pods, and potentially cause denial of service or access sensitive data. For example, an attacker could make the vLLM pod send malicious requests to an internal llm-d management endpoint, leading to system instability by falsely reporting metrics like the KV cache state. Version 0.14.1 contains a patch for the issue.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
vllmPyPI | < 0.14.1 | 0.14.1 |
Affected products
1Patches
1f46d576c54fb[Misc] Replace urllib's `urlparse` with urllib3's `parse_url` (#32746)
4 files changed · +23 −16
vllm/connections.py+2 −2 modified@@ -3,10 +3,10 @@ from collections.abc import Mapping, MutableMapping from pathlib import Path -from urllib.parse import urlparse import aiohttp import requests +from urllib3.util import parse_url from vllm.version import __version__ as VLLM_VERSION @@ -37,7 +37,7 @@ async def get_async_client(self) -> aiohttp.ClientSession: return self._async_client def _validate_http_url(self, url: str): - parsed_url = urlparse(url) + parsed_url = parse_url(url) if parsed_url.scheme not in ("http", "https"): raise ValueError(
vllm/envs.py+2 −2 modified@@ -442,9 +442,9 @@ def get_vllm_port() -> int | None: try: return int(port) except ValueError as err: - from urllib.parse import urlparse + from urllib3.util import parse_url - parsed = urlparse(port) + parsed = parse_url(port) if parsed.scheme: raise ValueError( f"VLLM_PORT '{port}' appears to be a URI. "
vllm/multimodal/utils.py+15 −10 modified@@ -9,13 +9,13 @@ from itertools import groupby from pathlib import Path from typing import TYPE_CHECKING, Any, TypeVar -from urllib.parse import ParseResult, urlparse from urllib.request import url2pathname import numpy as np import numpy.typing as npt import torch from PIL import Image, UnidentifiedImageError +from urllib3.util import Url, parse_url import vllm.envs as envs from vllm.connections import HTTPConnection, global_http_connection @@ -101,11 +101,14 @@ def __init__( def _load_data_url( self, - url_spec: ParseResult, + url_spec: Url, media_io: MediaIO[_M], ) -> _M: # type: ignore[type-var] - data_spec, data = url_spec.path.split(",", 1) + url_spec_path = url_spec.path or "" + data_spec, data = url_spec_path.split(",", 1) media_type, data_type = data_spec.split(";", 1) + # media_type starts with a leading "/" (e.g., "/video/jpeg") + media_type = media_type.lstrip("/") if data_type != "base64": msg = "Only base64 data URLs are supported for now." @@ -115,7 +118,7 @@ def _load_data_url( def _load_file_url( self, - url_spec: ParseResult, + url_spec: Url, media_io: MediaIO[_M], ) -> _M: # type: ignore[type-var] allowed_local_media_path = self.allowed_local_media_path @@ -124,7 +127,9 @@ def _load_file_url( "Cannot load local files without `--allowed-local-media-path`." ) - filepath = Path(url2pathname(url_spec.netloc + url_spec.path)) + url_spec_path = url_spec.path or "" + url_spec_netloc = url_spec.netloc or "" + filepath = Path(url2pathname(url_spec_netloc + url_spec_path)) if allowed_local_media_path not in filepath.resolve().parents: raise ValueError( f"The file path {filepath} must be a subpath " @@ -133,7 +138,7 @@ def _load_file_url( return media_io.load_file(filepath) - def _assert_url_in_allowed_media_domains(self, url_spec: ParseResult) -> None: + def _assert_url_in_allowed_media_domains(self, url_spec: Url) -> None: if ( self.allowed_media_domains and url_spec.hostname not in self.allowed_media_domains @@ -151,9 +156,9 @@ def load_from_url( *, fetch_timeout: int | None = None, ) -> _M: # type: ignore[type-var] - url_spec = urlparse(url) + url_spec = parse_url(url) - if url_spec.scheme.startswith("http"): + if url_spec.scheme and url_spec.scheme.startswith("http"): self._assert_url_in_allowed_media_domains(url_spec) connection = self.connection @@ -181,10 +186,10 @@ async def load_from_url_async( *, fetch_timeout: int | None = None, ) -> _M: - url_spec = urlparse(url) + url_spec = parse_url(url) loop = asyncio.get_running_loop() - if url_spec.scheme.startswith("http"): + if url_spec.scheme and url_spec.scheme.startswith("http"): self._assert_url_in_allowed_media_domains(url_spec) connection = self.connection
vllm/utils/network_utils.py+4 −2 modified@@ -11,12 +11,12 @@ Sequence, ) from typing import Any -from urllib.parse import urlparse from uuid import uuid4 import psutil import zmq import zmq.asyncio +from urllib3.util import parse_url import vllm.envs as envs from vllm.logger import init_logger @@ -217,13 +217,15 @@ def find_process_using_port(port: int) -> psutil.Process | None: def split_zmq_path(path: str) -> tuple[str, str, str]: """Split a zmq path into its parts.""" - parsed = urlparse(path) + parsed = parse_url(path) if not parsed.scheme: raise ValueError(f"Invalid zmq path: {path}") scheme = parsed.scheme host = parsed.hostname or "" port = str(parsed.port or "") + if host.startswith("[") and host.endswith("]"): + host = host[1:-1] # Remove brackets for IPv6 address if scheme == "tcp" and not all((host, port)): # The host and port fields are required for tcp
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-qh4c-xf7m-gxfcghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-24779ghsaADVISORY
- github.com/vllm-project/vllm/commit/f46d576c54fb8aeec5fc70560e850bed38ef17d7ghsax_refsource_MISCWEB
- github.com/vllm-project/vllm/pull/32746ghsax_refsource_MISCWEB
- github.com/vllm-project/vllm/security/advisories/GHSA-qh4c-xf7m-gxfcghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.