From 3738df3b93cb9ed02fba20ad285c6ec86e274272 Mon Sep 17 00:00:00 2001 From: Ernest Hysa <59969602+ErnestHysa@users.noreply.github.com> Date: Fri, 5 Jun 2026 14:12:47 +0100 Subject: [PATCH] fix(tasks): validate then_task_id belongs to same owner on create/update (#2764) then_task_id was stored without checking the target task's owner. A user could chain their task to execute any other user's task on success via the scheduler's _run_chained path. Now verifies the target task exists and belongs to the requesting user before storing. --- routes/task_routes.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/routes/task_routes.py b/routes/task_routes.py index 66049237d..38513b677 100644 --- a/routes/task_routes.py +++ b/routes/task_routes.py @@ -497,6 +497,15 @@ def setup_task_routes(task_scheduler) -> APIRouter: else bool(req.notifications_enabled) if req.notifications_enabled is not None else True ) + # Validate chained task belongs to same owner + if req.then_task_id: + chain_target = db.query(ScheduledTask).filter( + ScheduledTask.id == req.then_task_id + ).first() + if not chain_target: + raise HTTPException(400, "Chained task not found") + if chain_target.owner != user: + raise HTTPException(403, "Cannot chain to another user's task") task = ScheduledTask( id=task_id, owner=user, @@ -671,6 +680,14 @@ def setup_task_routes(task_scheduler) -> APIRouter: if req.trigger_count is not None: task.trigger_count = req.trigger_count if req.then_task_id is not None: + if req.then_task_id: + chain_target = db.query(ScheduledTask).filter( + ScheduledTask.id == req.then_task_id + ).first() + if not chain_target: + raise HTTPException(400, "Chained task not found") + if chain_target.owner != user: + raise HTTPException(403, "Cannot chain to another user's task") task.then_task_id = req.then_task_id or None if req.notifications_enabled is not None: task.notifications_enabled = bool(req.notifications_enabled)