This commit is contained in:
Timothy Jaeryang Baek
2026-05-09 21:05:49 +09:00
parent 2fa3b84241
commit df42d96c95
7 changed files with 22 additions and 10 deletions
+7
View File
@@ -824,6 +824,13 @@ else:
AIOHTTP_CLIENT_SESSION_SSL = os.environ.get('AIOHTTP_CLIENT_SESSION_SSL', 'True').lower() == 'true'
# When False (default), outbound HTTP requests do not follow 3xx redirects.
# This prevents redirect-based SSRF where a public URL 302-redirects to an
# internal address (RFC 1918, loopback, cloud-metadata 169.254.169.254).
# Set to True only if your deployment requires redirect following and you
# have other SSRF protections in place (e.g. egress firewall).
AIOHTTP_CLIENT_ALLOW_REDIRECTS = os.environ.get('AIOHTTP_CLIENT_ALLOW_REDIRECTS', 'False').lower() == 'true'
AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = os.environ.get(
'AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST',
os.environ.get('AIOHTTP_CLIENT_TIMEOUT_OPENAI_MODEL_LIST', '10'),
+2 -1
View File
@@ -43,6 +43,7 @@ from open_webui.retrieval.loaders.youtube import YoutubeLoader
from open_webui.env import (
AIOHTTP_CLIENT_TIMEOUT,
AIOHTTP_CLIENT_ALLOW_REDIRECTS,
OFFLINE_MODE,
ENABLE_FORWARD_USER_INFO_HEADERS,
AIOHTTP_CLIENT_SESSION_SSL,
@@ -185,7 +186,7 @@ def get_content_from_url(request, url: str) -> str:
# re-validation would let an attacker reach private IPs (RFC1918, loopback,
# cloud-metadata 169.254.169.254) via a public host that redirects internally.
try:
response = requests.get(url, stream=True, timeout=30, allow_redirects=False)
response = requests.get(url, stream=True, timeout=30, allow_redirects=AIOHTTP_CLIENT_ALLOW_REDIRECTS)
response.raise_for_status()
content_type = response.headers.get('Content-Type', '')
except Exception:
+3 -3
View File
@@ -48,7 +48,7 @@ from open_webui.config import (
WEB_FETCH_FILTER_LIST,
)
from open_webui.utils.misc import is_string_allowed
from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL
from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_ALLOW_REDIRECTS
log = logging.getLogger(__name__)
@@ -494,7 +494,7 @@ class SafeWebBaseLoader(WebBaseLoader):
# re-validation. Matches the policy enforced on the async _fetch() path below.
self.requests_kwargs = {
**(self.requests_kwargs or {}),
'allow_redirects': False,
'allow_redirects': AIOHTTP_CLIENT_ALLOW_REDIRECTS,
}
async def _fetch(self, url: str, retries: int = 3, cooldown: int = 2, backoff: float = 1.5) -> str:
@@ -513,7 +513,7 @@ class SafeWebBaseLoader(WebBaseLoader):
async with session.get(
url,
**(self.requests_kwargs | kwargs),
allow_redirects=False,
allow_redirects=AIOHTTP_CLIENT_ALLOW_REDIRECTS,
) as response:
if self.raise_for_status:
response.raise_for_status()
+2 -2
View File
@@ -22,7 +22,7 @@ from open_webui.config import (
)
from open_webui.constants import ERROR_MESSAGES
from open_webui.retrieval.web.utils import validate_url
from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, ENABLE_FORWARD_USER_INFO_HEADERS
from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_ALLOW_REDIRECTS, ENABLE_FORWARD_USER_INFO_HEADERS
from open_webui.utils.session_pool import get_session
from open_webui.models.chats import Chats
@@ -814,7 +814,7 @@ async def image_edits(
# public host that redirects internally (e.g. cloud-metadata exfil).
validate_url(data)
session = await get_session()
async with session.get(data, ssl=AIOHTTP_CLIENT_SESSION_SSL, allow_redirects=False) as r:
async with session.get(data, ssl=AIOHTTP_CLIENT_SESSION_SSL, allow_redirects=AIOHTTP_CLIENT_ALLOW_REDIRECTS) as r:
r.raise_for_status()
image_data = base64.b64encode(await r.read()).decode('utf-8')
+3 -1
View File
@@ -8,6 +8,8 @@ import aiohttp
import websockets
from pydantic import BaseModel
from open_webui.env import AIOHTTP_CLIENT_ALLOW_REDIRECTS
logger = logging.getLogger(__name__)
@@ -88,7 +90,7 @@ class JupyterCodeExecuter:
async with self.session.post(
'login',
data={'_xsrf': xsrf_token, 'password': self.password},
allow_redirects=False,
allow_redirects=AIOHTTP_CLIENT_ALLOW_REDIRECTS,
) as response:
response.raise_for_status()
self.session.cookie_jar.update_cookies(response.cookies)
+2 -1
View File
@@ -71,6 +71,7 @@ from open_webui.config import (
from open_webui.constants import ERROR_MESSAGES, WEBHOOK_MESSAGES
from open_webui.env import (
AIOHTTP_CLIENT_SESSION_SSL,
AIOHTTP_CLIENT_ALLOW_REDIRECTS,
WEBUI_NAME,
WEBUI_AUTH_COOKIE_SAME_SITE,
WEBUI_AUTH_COOKIE_SECURE,
@@ -740,7 +741,7 @@ class OAuthClientManager:
async with aiohttp.ClientSession(trust_env=True) as session:
async with session.get(
authorization_url,
allow_redirects=False,
allow_redirects=AIOHTTP_CLIENT_ALLOW_REDIRECTS,
ssl=AIOHTTP_CLIENT_SESSION_SSL,
) as resp:
if resp.status < 400:
+3 -2
View File
@@ -47,6 +47,7 @@ from open_webui.utils.access_control import has_access, has_connection_access
from open_webui.config import BYPASS_ADMIN_ACCESS_CONTROL
from open_webui.env import (
AIOHTTP_CLIENT_SESSION_SSL,
AIOHTTP_CLIENT_ALLOW_REDIRECTS,
AIOHTTP_CLIENT_TIMEOUT,
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER,
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA,
@@ -1433,7 +1434,7 @@ async def execute_tool_server(
headers=headers,
cookies=cookies,
ssl=AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL,
allow_redirects=False,
allow_redirects=AIOHTTP_CLIENT_ALLOW_REDIRECTS,
) as response:
if response.status >= 400:
text = await response.text()
@@ -1458,7 +1459,7 @@ async def execute_tool_server(
headers=headers,
cookies=cookies,
ssl=AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL,
allow_redirects=False,
allow_redirects=AIOHTTP_CLIENT_ALLOW_REDIRECTS,
) as response:
if response.status >= 400:
text = await response.text()