T09 · Insecure Skill Coding Practices
- Location
scripts/package_skill.py:24- Finding
Arbitrary File Inclusion Through Symbolic Links
- Content
View full analysis
list[Path]: """获取需要打包的安全文件列表""" safe_extensions = {".md", ".json", ".py", ".sh", ".txt", ".yaml", ".yml"} skip_dirs = {"__pycache__", ".git", "node_modules", ".venv"} skip_files = {".DS_Store", "Thumbs.db"} files = [] for root, dirs, filenames in os.walk(skill_path): # 过滤目录 dirs[:] = [d for d in dirs if d not in skip_dirs] root_path = Path(root) for filename in filenames: if filename in skip_files: continue file_path = root_path / filename if file_path.suffix in safe_extensions: files.append(file_path) return files ``` ```python # 添加所有安全文件 for file_path in get_safe_files(skill_path): rel_path = file_path.relative_to(skill_path) zf.write(file_path, rel_path) # 更新 manifest manifest["files"].append({ "path": str(rel_path), "checksum": calculate_checksum(file_path) }) ``` ### Technical Analysis The packaging allowlist validates only each candidate's filename extension. It does not reject symbolic links or resolve the candidate path and verify that the resulting target remains inside the Skill directory. `Path.relative_to(skill_path)` checks the lexical path collected during traversal, not the location reached after resolving a symbolic link. Consequently, a file such as `references/export.txt` can appear to reside under the Skill while pointing to an arbitrary readable file elsewhere on the host. Both `zf.write()` and `calculate_checksum()` follow the link and read the target. This flaw requires an attacker or untrusted contributor to b ...[truncated 1063 chars]- Remediation
View remediation
