Route user-supplied image-URL fetches through an SSRF-safe session (DNS rebinding, CWE-918) (#25960)
The connection-layer DNS-rebinding guard (_SSRFSafeResolver / _SSRFSafeAdapter, PR #24759) was mounted only on SafeWebBaseLoader. Two user-reachable image fetches validate the URL then fetch it through the shared get_session() pool with the default resolver, so a TTL-0 rebinding answer that passed validate_url reaches an internal address at connect: - get_image_base64_from_url (utils/files.py): user image_url on every chat completion. - load_url_image (routers/images.py, POST /api/v1/images/edit): user-supplied image field. Add get_ssrf_safe_session() (a one-off aiohttp session mounting _SSRFSafeResolver) and use it for both fetches, so the connect-time IP is re-validated and a rebound loopback / RFC1918 / metadata address is rejected. The shared pool is left untouched for the admin-configured image-generation callers, which legitimately reach internal hosts. Co-authored-by: dhyabi2 <32069256+dhyabi2@users.noreply.github.com> Co-authored-by: geo-chen <2404584+geo-chen@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
dhyabi2
geo-chen
Claude Opus 4.8
parent
d07e4154fe
commit
de8ea08f5c
@@ -46,7 +46,12 @@ from open_webui.config import (
|
||||
WEB_LOADER_TIMEOUT,
|
||||
)
|
||||
from open_webui.constants import ERROR_MESSAGES
|
||||
from open_webui.env import AIOHTTP_CLIENT_ALLOW_REDIRECTS, AIOHTTP_CLIENT_SESSION_SSL, USER_AGENT
|
||||
from open_webui.env import (
|
||||
AIOHTTP_CLIENT_ALLOW_REDIRECTS,
|
||||
AIOHTTP_CLIENT_SESSION_SSL,
|
||||
AIOHTTP_CLIENT_TIMEOUT,
|
||||
USER_AGENT,
|
||||
)
|
||||
from open_webui.retrieval.loaders.external_web import ExternalWebLoader
|
||||
from open_webui.retrieval.loaders.tavily import TavilyLoader
|
||||
from open_webui.retrieval.web.firecrawl import scrape_firecrawl_url
|
||||
@@ -197,6 +202,19 @@ class _SSRFSafeResolver(aiohttp.resolver.DefaultResolver):
|
||||
return results
|
||||
|
||||
|
||||
def get_ssrf_safe_session() -> aiohttp.ClientSession:
|
||||
"""A one-off aiohttp session that re-validates the connect-time IP via _SSRFSafeResolver,
|
||||
defeating DNS rebinding. Use for validate_url-gated fetches of user-supplied URLs that must
|
||||
not use the shared (rebinding-vulnerable) pool. Use as a context manager so it is closed:
|
||||
``async with get_ssrf_safe_session() as session: ...``.
|
||||
"""
|
||||
return aiohttp.ClientSession(
|
||||
connector=aiohttp.TCPConnector(resolver=_SSRFSafeResolver()),
|
||||
timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT),
|
||||
trust_env=True,
|
||||
)
|
||||
|
||||
|
||||
def extract_metadata(soup, url):
|
||||
metadata = {'source': url}
|
||||
if title := soup.find('title'):
|
||||
|
||||
Reference in New Issue
Block a user