1111
1212from __future__ import annotations
1313
14- import os
15- import shutil
1614import hashlib
1715import json
1816import logging
17+ import os
1918import re
19+ import shutil
2020import sys
2121import tarfile
2222import tempfile
@@ -80,6 +80,7 @@ def get_logger(
8080logger = get_logger ("monai.apps" )
8181__all__ .append ("logger" )
8282
83+
8384def _basename (p : PathLike ) -> str :
8485 """get the last part of the path (removing the trailing slash if it exists)"""
8586 sep = os .path .sep + (os .path .altsep or "" ) + "/ "
@@ -120,23 +121,25 @@ def update_to(self, b: int = 1, bsize: int = 1, tsize: int | None = None) -> Non
120121 logger .error (f"Download failed from { url } to { filepath } ." )
121122 raise e
122123
124+
123125def safe_extract_member (member , extract_to ):
124126 """Securely verify compressed package member paths to prevent path traversal attacks"""
125127 # Get member path (handle different compression formats)
126- if hasattr (member , ' filename' ):
128+ if hasattr (member , " filename" ):
127129 member_path = member .filename # zipfile
128- elif hasattr (member , ' name' ):
130+ elif hasattr (member , " name" ):
129131 member_path = member .name # tarfile
130132 else :
131133 member_path = str (member )
132134
133- if hasattr (member , 'issym' ) and member .issym ():
134- raise ValueError (f"Unsafe path: symlink { member_path } " )
135- if hasattr (member , 'islnk' ) and member .islnk ():
136- raise ValueError (f"Unsafe path: hardlink { member_path } " )
135+ if hasattr (member , "issym" ) and member .issym ():
136+ raise ValueError (f"Symbolic link detected in archive: { member_path } " )
137+ if hasattr (member , "islnk" ) and member .islnk ():
138+ raise ValueError (f"Hard link detected in archive: { member_path } " )
139+
137140 member_path = os .path .normpath (member_path )
138141
139- if os .path .isabs (member_path ) or '..' in member_path .split (os .sep ):
142+ if os .path .isabs (member_path ) or ".." in member_path .split (os .sep ):
140143 raise ValueError (f"Unsafe path detected in archive: { member_path } " )
141144
142145 full_path = os .path .join (extract_to , member_path )
@@ -150,6 +153,7 @@ def safe_extract_member(member, extract_to):
150153
151154 return full_path
152155
156+
153157def check_hash (filepath : PathLike , val : str | None = None , hash_type : str = "md5" ) -> bool :
154158 """
155159 Verify hash signature of specified file.
@@ -315,19 +319,19 @@ def extractall(
315319 logger .info (f"Writing into directory: { output_dir } ." )
316320 _file_type = file_type .lower ().strip ()
317321 if filepath .name .endswith ("zip" ) or _file_type == "zip" :
318- with zipfile .ZipFile (filepath , 'r' ) as zip_file :
322+ with zipfile .ZipFile (filepath , "r" ) as zip_file :
319323 for member in zip_file .infolist ():
320324 safe_path = safe_extract_member (member , output_dir )
321325 if member .is_dir ():
322326 continue
323327
324328 os .makedirs (os .path .dirname (safe_path ), exist_ok = True )
325329 with zip_file .open (member ) as source :
326- with open (safe_path , 'wb' ) as target :
330+ with open (safe_path , "wb" ) as target :
327331 shutil .copyfileobj (source , target )
328332 return
329333 if filepath .name .endswith ("tar" ) or filepath .name .endswith ("tar.gz" ) or "tar" in _file_type :
330- with tarfile .open (filepath , 'r' ) as tar_file :
334+ with tarfile .open (filepath , "r" ) as tar_file :
331335 for member in tar_file .getmembers ():
332336 safe_path = safe_extract_member (member , output_dir )
333337 if not member .isfile ():
@@ -337,7 +341,7 @@ def extractall(
337341 source = tar_file .extractfile (member )
338342 if source is not None :
339343 with source :
340- with open (safe_path , 'wb' ) as target :
344+ with open (safe_path , "wb" ) as target :
341345 shutil .copyfileobj (source , target )
342346 return
343347 raise NotImplementedError (
0 commit comments