T09 · Insecure Skill Coding Practices
- Location
scripts/download_files.py:97- Finding
Unsafe Archive Extraction Allows Path Traversal Outside the Workspace
- Content
View full analysis
Vulnerability Details
File Location:
scripts/download_files.py, lines 97-106
Vulnerability Type: Unsafe ZIP and TAR archive extraction
Risk Level: HighVulnerable Code
python if zipfile.is_zipfile(archive_path): print(f"解压 ZIP: {archive_path} -> {dest_dir}", file=sys.stderr) with zipfile.ZipFile(archive_path, 'r') as zf: zf.extractall(dest_dir) elif tarfile.is_tarfile(archive_path): print(f"解压 TAR: {archive_path} -> {dest_dir}", file=sys.stderr) with tarfile.open(archive_path, 'r:*') as tf: tf.extractall(dest_dir) else: raise ValueError(f"不支持的压缩格式: {archive_path}")Technical Analysis
The code extracts user-supplied ZIP and TAR archives using
extractall()without validating archive member names or types.Malicious archives can contain:
- Absolute paths.
- Paths containing
../traversal components. - TAR symbolic or hard links pointing outside the extraction directory.
- Special file entries or files targeting existing paths.
Consequently, an archive entry can resolve outside
dest_dirand overwrite or create files elsewhere with the privileges of the Skill process. This contradicts the statement inSKILL.mdthat extraction is limited to the workspace.The extraction behavior is required for the declared functionality, but unrestricted archive extraction exceeds the minimum privilege necessary. Each entry should be constrained to a regular file or directory beneath the designated workspace.
Attack Path
- An attacker creates a ZIP or TAR archive containing an entry such as
../../target-file, an absolute path, or a TAR link pointing outside the extraction directory. - The attacker provides the archive through
--code-urlor as a local code archive. download_and_extract()passes the archive toextract_archive().extract_archive()invokesZipFile.extractall()orTarFile.extractall()without member v ...[truncated 795 chars]
- Remediation
View remediation
Remediation Suggestions
- Resolve every archive member's destination using canonical paths before extraction.
- Verify that the resolved path is equal to or contained beneath the canonical extraction directory.
- Reject absolute paths, drive-qualified paths, null bytes, and paths containing traversal components.
- For TAR archives, reject symbolic links, hard links, device entries, FIFOs, and other special members unless explicitly required.
- On supported Python versions, apply a restrictive TAR extraction filter in addition to explicit path validation.
- Extract entries individually rather than calling unrestricted
extractall(). - Reject duplicate or conflicting paths and avoid overwriting existing files by default.
- Apply limits for archive member count, individual uncompressed size, and total uncompressed size to mitigate archive bombs.
- Extract into a newly created private temporary directory and move validated content into the workspace only after successful validation.
