@@ -53,15 +53,25 @@ def extract_zip(file_path: str, extract_to: str) -> None:
5353 max_size = 10 * 1024 * 1024 * 1024 # 10GB limit
5454
5555 with zipfile .ZipFile (file_path , "r" ) as zip_ref :
56+ # Get absolute path of extract_to for proper comparison
57+ extract_to_abs = os .path .abspath (extract_to )
58+
5659 # Security: Check for path traversal in zip entries
5760 for member in zip_ref .namelist ():
58- # Normalize the path and check for path traversal attempts
59- member_path = os .path .normpath (os .path .join (extract_to , member ))
60- if not member_path .startswith (os .path .abspath (extract_to )):
61- raise ValueError (f"Attempted path traversal in zip file: { member } " )
61+ # Check for explicit path traversal attempts first
6262 if ".." in member or member .startswith ("/" ):
6363 raise ValueError (f"Invalid path in zip file: { member } " )
6464
65+ # Normalize the member path (remove leading slashes and normalize)
66+ member_normalized = os .path .normpath (member .lstrip ("/" ))
67+
68+ # Join with extract_to and normalize to get the full path
69+ member_path = os .path .normpath (os .path .join (extract_to_abs , member_normalized ))
70+
71+ # Check if the resolved path is within extract_to directory
72+ if not member_path .startswith (extract_to_abs + os .sep ) and member_path != extract_to_abs :
73+ raise ValueError (f"Attempted path traversal in zip file: { member } " )
74+
6575 # Security: Check for zip bombs
6676 total_uncompressed_size = sum (info .file_size for info in zip_ref .infolist ())
6777 compression_ratio = total_uncompressed_size / file_size if file_size > 0 else 0
@@ -83,15 +93,25 @@ def extract_gz(file_path: str, extract_to: str) -> None:
8393def extract_tar (file_path : str , extract_to : str ) -> None :
8494 """Extract a tar file with security checks against path traversal."""
8595 with tarfile .open (file_path , "r:*" ) as tar_ref :
96+ # Get absolute path of extract_to for proper comparison
97+ extract_to_abs = os .path .abspath (extract_to )
98+
8699 # Security: Check for path traversal in tar entries
87100 for member in tar_ref .getmembers ():
88- # Normalize the path and check for path traversal attempts
89- member_path = os .path .normpath (os .path .join (extract_to , member .name ))
90- if not member_path .startswith (os .path .abspath (extract_to )):
91- raise ValueError (f"Attempted path traversal in tar file: { member .name } " )
101+ # Check for explicit path traversal attempts first
92102 if ".." in member .name or member .name .startswith ("/" ):
93103 raise ValueError (f"Invalid path in tar file: { member .name } " )
94104
105+ # Normalize the member path (remove leading slashes and normalize)
106+ member_normalized = os .path .normpath (member .name .lstrip ("/" ))
107+
108+ # Join with extract_to and normalize to get the full path
109+ member_path = os .path .normpath (os .path .join (extract_to_abs , member_normalized ))
110+
111+ # Check if the resolved path is within extract_to directory
112+ if not member_path .startswith (extract_to_abs + os .sep ) and member_path != extract_to_abs :
113+ raise ValueError (f"Attempted path traversal in tar file: { member .name } " )
114+
95115 tar_ref .extractall (extract_to )
96116 log .info (f"Extracted { file_path } to { extract_to } " )
97117
0 commit comments