T09 · Insecure Skill Coding Practices
- Location
scripts/export_fanqie.py:122- Finding
Unrestricted Output Cleanup Can Delete Unrelated TXT Files
- Content
View full analysis
Vulnerability Details
File Location:
scripts/export_fanqie.py, lines 122–129
Vulnerability Type: Unrestricted destructive file cleanup
Risk Level: MediumVulnerable Code
python out = args.out or (src / "番茄导出") if not out.is_absolute(): out = Path.cwd() / out chapters = collect_chapters(src) if not chapters: raise SystemExit(f"未找到章节 md(第*.md 或 001章*.md): {src}") out.mkdir(parents=True, exist_ok=True) for old in out.glob("*.txt"): if old.name != "目录.txt": old.unlink()Technical Analysis
The
--outargument accepts an arbitrary absolute or relative directory. The resolved output path is not required to remain under the source novel directory, nor is it verified as a dedicated export directory.Before generating output, the script enumerates every top-level
.txtfile in the selected directory and permanently deletes all of them except目录.txt. It does not verify whether each file was produced by a previous export, request confirmation, create a backup, or use a generated-file manifest.The documented export behavior does not disclose that unrelated TXT files in a custom output directory will be removed. This creates a destructive filesystem hazard when an existing directory is selected accidentally or through an incorrectly generated command.
Attack Path
- A user or agent invokes the exporter with
--outpointing to an existing writable directory containing unrelated TXT files. - The script accepts that directory without validating its relationship to the source directory.
out.glob("*.txt")enumerates all top-level TXT files in that directory.old.unlink()permanently deletes each enumerated file except one named目录.txt.- The script writes newly exported chapter files, potentially obscuring that unrelated files were removed.
This path requires the process to have write permission to the selected directory. It does not provide privilege escalation beyond the permissions already ...[truncated 570 chars]
- A user or agent invokes the exporter with
- Remediation
View remediation
Remediation Suggestions
- Resolve and validate both paths before performing filesystem operations:
python src = src.resolve() out = out.resolve() if not out.is_relative_to(src): raise SystemExit("The output directory must be located under the source directory.")-
Require a dedicated export subdirectory rather than accepting arbitrary output locations.
-
Remove only files known to have been generated by previous runs. Maintain a manifest containing generated filenames and restrict cleanup to entries in that manifest.
-
Do not clean an existing non-empty directory by default. Require an explicit
--cleanoption for destructive cleanup. -
Before deletion, display the exact files that would be removed and require confirmation in interactive use. For automated use, require an explicit force flag.
-
Consider writing into a newly created temporary directory and atomically replacing the prior export directory only after successful generation.
-
Document all cleanup behavior, including the effect of
--out, and clearly warn that destructive cleanup may occur. -
Add regression tests confirming that unrelated TXT files are preserved and that output paths outside the permitted source tree are rejected.
