From dc4924b66e655b315e3be4430a3e51b7d5c20acc Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Tue, 16 Jun 2026 22:45:42 +0200 Subject: [PATCH] Enforce per-model access on arena fallback before bypass_filter dispatch (#26046) generate_chat_completion() checks model access on line 200 only when bypass_filter is False. When an arena model reaches this function without a pre-resolved selected_model_id, which is the task and background path (the /api/v1/tasks/* endpoints call generate_chat_completion directly rather than through process_chat_payload), the fallback resolves the arena to an underlying model and recurses with bypass_filter=True, so the resolved model's access check is skipped. An authenticated user with access to an arena could therefore reach a model they are denied directly, and for the default or exclude arena, whose candidate pool is every non-arena model, any model on the instance (CWE-862). The normal chat path resolves the arena in process_chat_payload before this function, so its resolved model is checked on line 200; the task path was not, which is the inconsistency. Enforce check_model_access() on the resolved model in the fallback, before the bypass_filter=True recursion, mirroring the normal-path check. Admins and already-bypassed recursive calls are unaffected, and legitimate arena use of accessible models is unchanged. Co-authored-by: rexpository <30176934+rexpository@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) --- backend/open_webui/utils/chat.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend/open_webui/utils/chat.py b/backend/open_webui/utils/chat.py index 248be33be7..196689f61d 100644 --- a/backend/open_webui/utils/chat.py +++ b/backend/open_webui/utils/chat.py @@ -237,6 +237,12 @@ async def generate_chat_completion( form_data['model'] = selected_model_id + # bypass_filter recursion below skips the line-200 check; gate the resolved model here. + if not bypass_filter and user.role == 'user': + selected_model = request.app.state.MODELS.get(selected_model_id) + if selected_model: + await check_model_access(user, selected_model) + if selected_model_id: if form_data.get('stream') == True: