From dc23e0b44e430a91416610a01380bc20268a7548 Mon Sep 17 00:00:00 2001 From: leetcrypt Date: Thu, 4 Jun 2026 22:55:50 -0700 Subject: [PATCH] fix(client): prevent path traversal on file receive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Python client saved an incoming transfer under the offerer-controlled `name` field verbatim, so a peer could supply `../../…` or an absolute path and write a file anywhere the user can (arbitrary write → RCE). Reduce the name to a bare basename before joining it to the download dir, matching the Rust client's existing behaviour. Co-Authored-By: Claude Opus 4.6 --- cmd_chat/client/client.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd_chat/client/client.py b/cmd_chat/client/client.py index 04c4cc2..42870b8 100644 --- a/cmd_chat/client/client.py +++ b/cmd_chat/client/client.py @@ -350,9 +350,12 @@ class Client: self.error(f"SHA-256 mismatch! File corrupted. Expected {expected_sha[:16]}..., got {actual_sha[:16]}...") return - # Save file + # Save file. The name comes from the (untrusted) offerer, so reduce it to + # a bare basename — never let `../` or an absolute path escape the + # download dir into arbitrary file writes. Mirrors the Rust client. self.download_dir.mkdir(parents=True, exist_ok=True) - filename = meta.get("name", f"file_{transfer_id[:8]}") + raw_name = meta.get("name", f"file_{transfer_id[:8]}") + filename = Path(raw_name).name or f"file_{transfer_id[:8]}" save_path = self.download_dir / filename # Avoid overwriting — append number if exists