diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000000..4bd17a68ce --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2023-10-27 - Path traversal in skill zip extraction +**Vulnerability:** Path traversal vulnerability due to unchecked zip file extraction. +**Learning:** `zipfile.ZipFile.extractall()` is vulnerable to directory traversal attacks if the zip file contains relative paths like `../`. +**Prevention:** Always validate every path in the archive using `os.path.abspath` and `str.startswith` instead of `.resolve()` or `.is_relative_to()` before extracting to prevent path traversal while maintaining performance. diff --git a/helpers/skills_import.py b/helpers/skills_import.py index c73ffa55de..053c074c67 100644 --- a/helpers/skills_import.py +++ b/helpers/skills_import.py @@ -94,6 +94,12 @@ def _unzip_to_temp_dir(zip_path: Path) -> Path: target.mkdir(parents=True, exist_ok=True) with zipfile.ZipFile(zip_path, "r") as z: + target_abs = os.path.abspath(str(target)) + target_prefix = target_abs + ("" if target_abs.endswith(os.sep) else os.sep) + for member in z.namelist(): + member_path = os.path.abspath(os.path.join(target_abs, member)) + if not member_path.startswith(target_prefix): + raise ValueError(f"Unsafe path in archive: {member}") z.extractall(target) # If zip contains a single top-level folder, treat that as the root