From 8e769d6486b59e8e2f7036e0bdf32fd494d1a795 Mon Sep 17 00:00:00 2001 From: painbaba Date: Sat, 29 Aug 2026 20:40:36 +0530 Subject: [PATCH] fix: prevent path traversal in websocket handle_data file reads file_name stored in raw records is client-influenced (it can be polluted via /conv/community), but handle_data() joined it into root_dir/workspace and read the file without any containment check, allowing relative traversal and absolute-path overrides to read arbitrary files as base64 on the /ws/base websocket. Resolve the candidate path and require it to stay inside the interaction workspace before reading. Fixes #437 --- XAgentServer/application/websockets/common.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/XAgentServer/application/websockets/common.py b/XAgentServer/application/websockets/common.py index 728f519..220d8cb 100644 --- a/XAgentServer/application/websockets/common.py +++ b/XAgentServer/application/websockets/common.py @@ -43,9 +43,13 @@ def handle_data(row: Raw, root_dir: str): file_name = output['file_name'] png_base64 = None if file_name: - file_path = os.path.join( - root_dir, "workspace", file_name) - if os.path.exists(file_path): + # file_name comes from stored raws and is client-influenced: + # resolve it and never read outside the interaction workspace + workspace_dir = os.path.realpath( + os.path.join(root_dir, "workspace")) + file_path = os.path.realpath( + os.path.join(workspace_dir, file_name)) + if file_path.startswith(workspace_dir + os.sep) and os.path.isfile(file_path): try: with open(file_path, "rb") as f: png_base64 = base64.b64encode(