T09 · Insecure Skill Coding Practices
Warning
- Location
- templates/compress.py:120
- Finding
- Destructive Cleanup of an Unvalidated Existing Destination Directory<![CDATA[ ## Vulnerability Details **File Location**: `templates/compress.py`, lines 120-135 **Vulnerability Type**: Unsafe recursive file deletion **Risk Level**: Medium ### Vulnerable Code ```python # ---- 清理未引用文件(v1.5 强制)---- if not keep_unreferenced and dst_html_paths: referenced = _collect_referenced(src_dir, dst_html_paths) removed = 0 for root, dirs, files in os.walk(dst_dir): for f in files: if f.lower().endswith('.html'): continue rel = os.path.relpath(os.path.join(root, f), dst_dir) rel_norm = rel.replace('\\', '/') # 被引用(用不带扩展名的键匹配,因引用可能来自改写前的 .png) base = os.path.splitext(rel_norm)[0] if rel_norm in referenced or (base + '.jpg') in referenced: continue try: os.remove(os.path.join(root, f)) ``` ### Technical Analysis The destination directory is supplied as a command-line argument and initialized using `os.makedirs(dst_dir, exist_ok=True)`. The script does not require the destination to be new or empty and does not verify that it is a dedicated publication directory. During default operation, the cleanup block recursively traverses the entire destination and deletes every non-HTML file that does not appear in the generated HTML references. The deletion criteria do not distinguish files generated during the current run from files that already existed in the destination. Although the script does not provide remote code execution or privilege escalation, it performs destructive operations over a user-selected path without sufficient safety checks. ### Attack Path 1. A user, automation system, or calling Agent supplies an existing directory as the `dst` argument. 2. The script accepts the directory because `exist_ok=True` permits pre-existing destinations. 3. At least one HTML file is copied, causing `dst_html_paths` to become non-empty. 4. Default cleanup recursively walks the entire destination. ...[truncated 637 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Require the destination to be absent or empty by default. 2. Refuse to proceed when unrelated files are present unless the user supplies an explicit option such as `--force-clean`. 3. Resolve source and destination with `os.path.realpath()` and reject dangerous destinations, including: - The filesystem root. - The user's home directory. - The source directory itself. - Any parent directory of the source. 4. Track files created during the current execution and delete only those tracked files. 5. Generate output in a new temporary directory and atomically rename it to the final publication directory after successful completion. 6. Display the resolved destination and planned deletion count before destructive cleanup. 7. Do not silently suppress deletion failures; report affected paths and return a nonzero status if cleanup is incomplete. ]]>
