T09 · Insecure Skill Coding Practices
- Location
scripts/generate_report.py:502- Finding
Path Traversal Through Unsanitized Report and Chart Paths
- Content
View full analysis
str: """ 保存报告到文件 """ if output_dir is None: output_dir = os.path.expanduser( f"~/.openclaw/workspace/reports/stock/{self.stock_name}" ) os.makedirs(output_dir, exist_ok=True) date_str = self.date.replace("-", "") filename = f"{self.stock_name}_{report_type}_{date_str}.md" filepath = os.path.join(output_dir, filename) with open(filepath, 'w', encoding='utf-8') as f: f.write(report) return filepath ``` ```python # scripts/generate_report.py:729-747 if len(sys.argv) >= 4: stock_name = sys.argv[1] stock_code = sys.argv[2] report_type = sys.argv[3] # 午间复盘 / 全天复盘 date = sys.argv[4] if len(sys.argv) > 4 else None else: stock_name = "示例股票" stock_code = "000001.SZ" report_type = "全天复盘" date = None generator = StockReportGenerator(stock_name, stock_code) if date: generator.date = date ``` ### Technical Analysis The command-line values `stock_name` and `date` are accepted without validation. Both values are subsequently included in filesystem paths. In particular, `stock_name` is used as a directory component and again as part of the report and chart filenames. Python's `os.path.join()` does not enforce containment beneath the intended report directory. Inputs containing path separators or parent-directory components such as `../` can therefore cause the resulting path to resolve outside ` ...[truncated 2048 chars]- Remediation
View remediation
str: if not re.fullmatch(r"[\w -]{1,80}", value, flags=re.UNICODE): raise ValueError("Invalid stock name") if value in {".", ".."}: raise ValueError("Invalid stock name") return value safe_name = safe_stock_component(self.stock_name) safe_date = datetime.strptime(self.date, "%Y-%m-%d").strftime("%Y%m%d") destination_dir = (REPORT_ROOT / safe_name).resolve() if REPORT_ROOT not in destination_dir.parents: raise ValueError("Output path escapes the report root") destination_dir.mkdir(parents=True, exist_ok=True) filepath = (destination_dir / f"{safe_name}_{report_type}_{safe_date}.md").resolve() if destination_dir not in filepath.parents: raise ValueError("Output file escapes the report directory") ``` 6. Use exclusive creation mode (`x`) where overwriting is unnecessary, or require explicit authorization before replacing an existing report. 7. Apply the same validation and containment checks to the radar-chart path and to any caller-provided `output_dir`. ]]>
