Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 08ec477

Browse files
fix(get.py): Add path validation for archives
1 parent f2697f3 commit 08ec477

File tree

1 file changed

+50
-3
lines changed

1 file changed

+50
-3
lines changed

‎tools/get.py

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,49 @@
5050
dist_dir = current_dir + "/dist/"
5151

5252

53+
def is_safe_archive_path(path):
54+
# Check for absolute paths (both Unix and Windows style)
55+
if path.startswith('/') or (len(path) > 1 and path[1] == ':' and path[2] in '\\/'):
56+
raise ValueError(f"Absolute path not allowed: {path}")
57+
58+
# Normalize the path to handle any path separators
59+
normalized_path = os.path.normpath(path)
60+
61+
# Check for directory traversal attempts using normalized path
62+
if ".." in normalized_path.split(os.sep):
63+
raise ValueError(f"Directory traversal not allowed: {path}")
64+
65+
# Additional check for paths that would escape the target directory
66+
if normalized_path.startswith(".."):
67+
raise ValueError(f"Path would escape target directory: {path}")
68+
69+
# Check for any remaining directory traversal patterns in the original path
70+
# This catches cases that might not be normalized properly
71+
path_parts = path.replace('\\', '/').split('/')
72+
if '..' in path_parts:
73+
raise ValueError(f"Directory traversal not allowed: {path}")
74+
75+
return True
76+
77+
78+
def safe_tar_extract(tar_file, destination):
79+
# Validate all paths before extraction
80+
for member in tar_file.getmembers():
81+
is_safe_archive_path(member.name)
82+
83+
# If all paths are safe, proceed with extraction
84+
tar_file.extractall(destination, filter="tar")
85+
86+
87+
def safe_zip_extract(zip_file, destination):
88+
# Validate all paths before extraction
89+
for name in zip_file.namelist():
90+
is_safe_archive_path(name)
91+
92+
# If all paths are safe, proceed with extraction
93+
zip_file.extractall(destination)
94+
95+
5396
def sha256sum(filename, blocksize=65536):
5497
hash = hashlib.sha256()
5598
with open(filename, "rb") as f:
@@ -212,6 +255,10 @@ def unpack(filename, destination, force_extract, checksum): # noqa: C901
212255
print("File corrupted or incomplete!")
213256
cfile = None
214257
file_is_corrupted = True
258+
except ValueError as e:
259+
print(f"Security validation failed: {e}")
260+
cfile = None
261+
file_is_corrupted = True
215262

216263
if file_is_corrupted:
217264
corrupted_filename = filename + ".corrupted"
@@ -243,15 +290,15 @@ def unpack(filename, destination, force_extract, checksum): # noqa: C901
243290
if filename.endswith("tar.gz"):
244291
if not cfile:
245292
cfile = tarfile.open(filename, "r:gz")
246-
cfile.extractall(destination, filter="tar")
293+
safe_tar_extract(cfile, destination)
247294
elif filename.endswith("tar.xz"):
248295
if not cfile:
249296
cfile = tarfile.open(filename, "r:xz")
250-
cfile.extractall(destination, filter="tar")
297+
safe_tar_extract(cfile, destination)
251298
elif filename.endswith("zip"):
252299
if not cfile:
253300
cfile = zipfile.ZipFile(filename)
254-
cfile.extractall(destination)
301+
safe_zip_extract(cfile, destination)
255302
else:
256303
raise NotImplementedError("Unsupported archive type")
257304

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /