From 471988110500cc670f1b5795ae4112babcaca3ee Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 31 May 2026 23:53:53 +0200 Subject: [PATCH] fix: move bypass_system_prompt off query parameter onto request.state (#25156) bypass_system_prompt is an internal flag used by utils/middleware.py and utils/chat.py to skip applying the model system prompt on recursive base-model calls, but it was still declared as a positional argument on the openai/ollama chat-completion route handlers, so FastAPI bound it from the query string. Move it to request.state so external clients cannot set it, matching how bypass_filter is handled. Drop the argument from both route signatures and read getattr(request.state, 'bypass_system_prompt', False); utils/chat.py sets request.state.bypass_system_prompt alongside bypass_filter and drops the kwarg from the two route-handler calls (the recursive self-calls keep it). Mirrors c0385f60b. Co-authored-by: anishgirianish <161533316+anishgirianish@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) --- backend/open_webui/routers/ollama.py | 9 +++++---- backend/open_webui/routers/openai.py | 9 +++++---- backend/open_webui/utils/chat.py | 8 ++++---- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/backend/open_webui/routers/ollama.py b/backend/open_webui/routers/ollama.py index b217d90a92..4586189f7b 100644 --- a/backend/open_webui/routers/ollama.py +++ b/backend/open_webui/routers/ollama.py @@ -974,7 +974,6 @@ async def generate_chat_completion( form_data: dict, url_idx: int | None = None, user=Depends(get_verified_user), # noqa: B008 - bypass_system_prompt: bool = False, ): """Forward a chat completion request to an Ollama backend.""" if not request.app.state.config.ENABLE_OLLAMA_API: @@ -985,12 +984,14 @@ async def generate_chat_completion( # This prevents holding a connection during the entire LLM call (30-60+ seconds), # which would exhaust the connection pool under concurrent load. - # bypass_filter is read from request.state to prevent external clients from - # setting it via query parameter (CVE fix). Only internal server-side callers - # (e.g. utils/chat.py) should set request.state.bypass_filter = True. + # bypass_filter and bypass_system_prompt are read from request.state to prevent + # external clients from setting them via query parameter. Only internal + # server-side callers (e.g. utils/chat.py) should set + # request.state.bypass_filter / request.state.bypass_system_prompt = True. bypass_filter = getattr(request.state, 'bypass_filter', False) if BYPASS_MODEL_ACCESS_CONTROL: bypass_filter = True + bypass_system_prompt = getattr(request.state, 'bypass_system_prompt', False) metadata = form_data.pop('metadata', None) try: diff --git a/backend/open_webui/routers/openai.py b/backend/open_webui/routers/openai.py index 66d6142f94..b2ada1c8a3 100644 --- a/backend/open_webui/routers/openai.py +++ b/backend/open_webui/routers/openai.py @@ -1045,19 +1045,20 @@ async def generate_chat_completion( request: Request, form_data: dict, user=Depends(get_verified_user), - bypass_system_prompt: bool = False, ): # NOTE: We intentionally do NOT use Depends(get_async_session) here. # Database operations (get_model_by_id, AccessGrants.has_access) manage their own short-lived sessions. # This prevents holding a connection during the entire LLM call (30-60+ seconds), # which would exhaust the connection pool under concurrent load. - # bypass_filter is read from request.state to prevent external clients from - # setting it via query parameter (CVE fix). Only internal server-side callers - # (e.g. utils/chat.py) should set request.state.bypass_filter = True. + # bypass_filter and bypass_system_prompt are read from request.state to prevent + # external clients from setting them via query parameter. Only internal + # server-side callers (e.g. utils/chat.py) should set + # request.state.bypass_filter / request.state.bypass_system_prompt = True. bypass_filter = getattr(request.state, 'bypass_filter', False) if BYPASS_MODEL_ACCESS_CONTROL: bypass_filter = True + bypass_system_prompt = getattr(request.state, 'bypass_system_prompt', False) idx = 0 diff --git a/backend/open_webui/utils/chat.py b/backend/open_webui/utils/chat.py index 0884528597..248be33be7 100644 --- a/backend/open_webui/utils/chat.py +++ b/backend/open_webui/utils/chat.py @@ -160,9 +160,11 @@ async def generate_chat_completion( if BYPASS_MODEL_ACCESS_CONTROL: bypass_filter = True - # Propagate bypass_filter via request.state so that downstream route - # handlers (openai/ollama) can read it without exposing it as a query param. + # Propagate bypass_filter and bypass_system_prompt via request.state so that + # downstream route handlers (openai/ollama) can read them without exposing + # them as query parameters. request.state.bypass_filter = bypass_filter + request.state.bypass_system_prompt = bypass_system_prompt if hasattr(request.state, 'metadata'): if 'metadata' not in form_data: @@ -279,7 +281,6 @@ async def generate_chat_completion( request=request, form_data=form_data, user=user, - bypass_system_prompt=bypass_system_prompt, ) if form_data.get('stream'): response.headers['content-type'] = 'text/event-stream' @@ -295,7 +296,6 @@ async def generate_chat_completion( request=request, form_data=form_data, user=user, - bypass_system_prompt=bypass_system_prompt, )