From 419d248093f2754ff7c9e258517034c7a825a6e1 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 21 Sep 2026 16:46:48 +0200 Subject: [PATCH] refac: check the timer owner's role before running a due timer (#30220) The due-timer executor rehydrates the owner from the database and now verifies that the owner is still a user or an admin before entering the chat completion pipeline, mirroring the check the scheduled-automation executor already performs. A timer whose owner no longer qualifies is recorded as an error instead of being run. --- backend/open_webui/utils/timers.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend/open_webui/utils/timers.py b/backend/open_webui/utils/timers.py index 094a2130c8..d8be899dff 100644 --- a/backend/open_webui/utils/timers.py +++ b/backend/open_webui/utils/timers.py @@ -17,6 +17,7 @@ from open_webui.models.chat_messages import ChatMessages from open_webui.models.chats import Chat, ChatForm, Chats from open_webui.models.users import UserModel, Users from open_webui.tasks import has_active_tasks +from open_webui.utils.auth import VERIFIED_USER_ROLES from open_webui.utils.json_codec import JSONCodec from open_webui.utils.misc import get_message_list from sqlalchemy import select @@ -258,6 +259,11 @@ async def execute_due_timer(app, timer_id: str, claim_id: str | None = None) -> await _set_timer_state(timer_id, 'error', timer_error='timer user no longer exists') return + # Re-gate the rehydrated owner: a demoted owner must not run. + if user.role not in VERIFIED_USER_ROLES: + await _set_timer_state(timer_id, 'error', timer_error='owner no longer permitted to run timers') + return + run = meta.get('run') or {} model_id = run.get('model_id') or meta.get('timer_model_id') if not model_id: