-
Notifications
You must be signed in to change notification settings - Fork 1.2k
fix: Enhancements Needed for Secure Tar Extraction (5560) #5726
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6c6b0a6
b8c6e49
f4eee66
ad3e58b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1688,7 +1688,11 @@ def _is_bad_path(path, base): | |
| bool: True if the path is not rooted under the base directory, False otherwise. | ||
| """ | ||
| # joinpath will ignore base if path is absolute | ||
| return not _get_resolved_path(joinpath(base, path)).startswith(base) | ||
| resolved = _get_resolved_path(joinpath(base, path)) | ||
|
aviruthen marked this conversation as resolved.
aviruthen marked this conversation as resolved.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The resolved = _get_resolved_path(joinpath(base, path))
base = _get_resolved_path(base) # ensure consistent normalization
try:
return os.path.commonpath([resolved, base]) != base
except ValueError:
return TrueOtherwise, if |
||
| try: | ||
| return os.path.commonpath([resolved, base]) != base | ||
| except ValueError: | ||
| return True # If we can't determine safety, treat as bad path | ||
|
|
||
|
|
||
| def _is_bad_link(info, base): | ||
|
|
@@ -1704,23 +1708,26 @@ def _is_bad_link(info, base): | |
| bool: True if the link is not rooted under the base directory, False otherwise. | ||
| """ | ||
| # Links are interpreted relative to the directory containing the link | ||
| # Wrap with _get_resolved_path to ensure consistent normalization for commonpath comparison | ||
| tip = _get_resolved_path(joinpath(base, dirname(info.name))) | ||
| return _is_bad_path(info.linkname, base=tip) | ||
|
|
||
|
|
||
|
aviruthen marked this conversation as resolved.
|
||
| def _get_safe_members(members): | ||
| def _get_safe_members(members, base=None): | ||
| """A generator that yields members that are safe to extract. | ||
|
|
||
| It filters out bad paths and bad links. | ||
|
|
||
| Args: | ||
| members (list): A list of members to check. | ||
| members (list): A list of TarInfo members to check. | ||
| base (str): The base directory for extraction. If None, defaults to the | ||
| current working directory (for backward compatibility). | ||
|
|
||
|
aviruthen marked this conversation as resolved.
|
||
| Yields: | ||
| tarfile.TarInfo: The tar file info. | ||
| """ | ||
| base = _get_resolved_path("") | ||
|
|
||
| if base is None: | ||
| base = _get_resolved_path("") | ||
| for file_info in members: | ||
| if _is_bad_path(file_info.name, base): | ||
| logger.error("%s is blocked (illegal path)", file_info.name) | ||
|
|
@@ -1783,7 +1790,8 @@ def custom_extractall_tarfile(tar, extract_path): | |
| if hasattr(tarfile, "data_filter"): | ||
| tar.extractall(path=extract_path, filter="data") | ||
| else: | ||
| tar.extractall(path=extract_path, members=_get_safe_members(tar)) | ||
| base = _get_resolved_path(extract_path) | ||
|
aviruthen marked this conversation as resolved.
|
||
| tar.extractall(path=extract_path, members=_get_safe_members(tar.getmembers(), base)) | ||
| # Re-validate extracted paths to catch symlink race conditions | ||
| _validate_extracted_paths(extract_path) | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.