T09 · Insecure Skill Coding Practices
- Location
scripts/material_summary.py:236- Finding
Unintended Report Overwrite Due to Unsafe Output Path Derivation
- Content
View full analysis
Vulnerability Details
File Location:
scripts/material_summary.py, lines 236–256
Vulnerability Type: Unsafe file path derivation and unintended file overwrite
Risk Level: LowComplete Code Snippet
python if args.output: with open(args.output, "w", encoding="utf-8") as f: f.write(report) print(f"✓ 材料报告已保存:{args.output}") else: print(report) # 同时输出 JSON 格式便于程序处理 json_output = { "period": { "start": period_start.strftime("%Y-%m-%d"), "end": period_end.strftime("%Y-%m-%d") }, "materials": materials, "purchase_plan": purchase_plan } if args.output: json_path = args.output.replace(".md", ".json") with open(json_path, "w", encoding="utf-8") as f: json.dump(json_output, f, ensure_ascii=False, indent=2) print(f"✓ JSON 数据已保存:{json_path}")Technical Analysis
The script writes the Markdown report directly to the user-supplied
--outputpath. It then derives a companion JSON path using:python json_path = args.output.replace(".md", ".json")If the output path does not contain the exact substring
.md,str.replace()returns the original path unchanged. Consequently, the JSON write targets the same file that was just used for the Markdown report and silently replaces its contents.The script also opens both destinations in write mode without checking whether the paths are identical or whether an existing file would be overwritten. This is an integrity flaw in local file handling rather than a command-execution, privilege-escalation, or data-exfiltration vulnerability.
Attack Path
-
Prepare a valid schedule file containing tasks with estimable material requirements.
-
Invoke the script with an output filename that does not contain
.md:bash python3 scripts/material_summary.py \ --schedule schedule.json \ --output report.txt -
The script ...[truncated 886 chars]
-
- Remediation
View remediation
Remediation Suggestions
-
Use
pathlib.Path.with_suffix()rather than raw string replacement:python from pathlib import Path report_path = Path(args.output) json_path = report_path.with_suffix(".json") -
Verify that the two destinations are different before either write:
python if report_path.resolve() == json_path.resolve(): raise ValueError("Report and JSON output paths must be different") -
Validate the report extension or require separate explicit options such as
--report-outputand--json-output. -
Avoid silently replacing existing files. Reject an existing destination unless the caller supplies an explicit
--overwriteoption. -
Use atomic writes through temporary files followed by
os.replace()after successful serialization, reducing the chance of partially written or corrupted output. -
Add regression tests for output names including
report.md,report.txt,report, uppercase suffixes, multiple suffixes, and pre-existing destination files.
-
