From 706ea6a7b7f8e610b7f4ab330ae038fb53a8e139 Mon Sep 17 00:00:00 2001 From: Wes Huber Date: Sun, 7 Jun 2026 07:44:26 -0700 Subject: [PATCH] fix: TOCTOU race in personal file delete + IndexError on whitespace cmd (#2228) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. routes/personal_routes.py: os.path.exists() then os.remove() is a classic TOCTOU race — another request or cleanup can delete the file between the check and the remove, raising FileNotFoundError. Replace with try/except FileNotFoundError. 2. src/tool_implementations.py: cmd.split()[0] crashes with IndexError when cmd is a non-empty whitespace-only string (split() returns []). Guard with (cmd.split() or [''])[0]. Co-authored-by: Claude Opus 4.6 (1M context) --- routes/personal_routes.py | 9 ++++++--- src/tool_implementations.py | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/routes/personal_routes.py b/routes/personal_routes.py index 77526c1d1..e47fbbd7c 100644 --- a/routes/personal_routes.py +++ b/routes/personal_routes.py @@ -286,9 +286,12 @@ def setup_personal_routes(personal_docs_manager, rag_manager, rag_available): except ValueError: # commonpath raises on mixed drives / non-comparable paths in_uploads = False - if in_uploads and abs_target != base_abs and os.path.exists(abs_target): - os.remove(abs_target) - deleted_from_disk = True + if in_uploads and abs_target != base_abs: + try: + os.remove(abs_target) + deleted_from_disk = True + except FileNotFoundError: + pass # already gone — race with another request or cleanup # Exclude the file from the listing (persists across restarts) personal_docs_manager.exclude_file(filepath) diff --git a/src/tool_implementations.py b/src/tool_implementations.py index 316588b0b..90d9dae05 100644 --- a/src/tool_implementations.py +++ b/src/tool_implementations.py @@ -2662,7 +2662,7 @@ async def _cookbook_register_task(session_id: str, model: str, host: str, placeholder = ( f"Launched via agent — waiting for tmux output…\n" f" session: {session_id}\n" - f" target: {target}{cmd.split()[0] if cmd else ''}\n" + f" target: {target}{(cmd.split() or [''])[0] if cmd else ''}\n" f" cmd: {cmd[:200]}{'…' if len(cmd) > 200 else ''}" ) tasks.append({