11import ntpath
22import os
33from os .path import join , getsize , exists
4+ from pathlib import PurePosixPath
45from nxc .helpers .misc import CATEGORY
56from nxc .paths import NXC_PATH
67
@@ -84,9 +85,12 @@ def on_admin_login(self, context, connection):
8485 continue
8586
8687 remote_file_path = ntpath .join (screenshot_path , remote_file_name )
87- sanitized_path = screenshot_path .replace ("\\ " , "_" ).replace ("/" , "_" )
88- local_file_name = f"{ folder_name } _{ sanitized_path } _{ remote_file_name } "
89- local_file_path = join (user_output_dir , local_file_name )
88+ # replace \\ with underscores and ignore absolute path or path traversal attempts
89+ clean_screenshot_path = "_" .join (p for p in PurePosixPath (screenshot_path .replace ("\\ " , "/" )).parts if p not in (".." , "." , "/" ))
90+ clean_file = "_" .join (p for p in PurePosixPath (remote_file_name .replace ("\\ " , "/" )).parts if p not in (".." , "." , "/" ))
91+
92+ local_file_path = join (user_output_dir , f"{ clean_screenshot_path } _{ clean_file } " )
93+ context .log .debug (f"{ local_file_path = } " )
9094
9195 try :
9296 with open (local_file_path , "wb" ) as local_file :
@@ -107,7 +111,7 @@ def on_admin_login(self, context, connection):
107111 context .log .debug (f"Failed to download '{ remote_file_path } ' for user { folder_name } : { e } " )
108112
109113 if total_files_downloaded > 0 and host_output_path :
110- context .log .success (f"{ total_files_downloaded } file(s) downloaded from host { connection .host } to { host_output_path } . " )
114+ context .log .success (f"{ total_files_downloaded } file(s) downloaded from host { connection .host } to { host_output_path } / " )
111115
112116 def find_screenshots_folders (self , user_folder_name ):
113117 """
0 commit comments