T09 · Insecure Skill Coding Practices
- Location
scripts/make_report_html.py:11- Finding
Unescaped Report Data and Unrestricted Path Construction
- Content
View full analysis
1 else "golden_cross" import os res_file = f"{BASE}/full_attribution_result_{strat}.json" if not os.path.exists(res_file): res_file = f"{BASE}/full_attribution_result.json" D = json.load(open(res_file, encoding="utf-8")) ``` ```python q_rows = "" for k, v in A.get("quarters", {}).items(): cls = "pos" if str(v).startswith("+") else "neg" q_rows += f"{k}{v}" ``` ```python qs = D["quarter_share"] qmax = max(qs.values()) if qs else 1 qbar = "" for q, v in qs.items(): w = v / qmax * 100 qbar += f"""{q}""" ``` ```python{v*100:.1f}%{M['date_range']} · {M['n_stocks']:,} 只股票 · stock-deep-backtest 技能 · 计算耗时 {M['runtime_s']}s``` ```python OUT = f"{BASE}/full_attribution_report_{strat}.html" open(OUT, "w", encoding="utf-8").write(HTML) ``` ### Technical Analysis The renderer correctly applies `html.escape()` to some values, such as factor names and the strategy title, but it directly interpolates other JSON-derived strings into the generated HTML. In particular, quarter keys, quarter values, and metadata such as `date_range` are inserted without contextual HTML escaping. If an attacker can modify a consumed `base_*.json` or `full_attribution_result_*.json` file, those fields can contain HTML elements or script-capable markup. The resulting payload becomes part of the generated report and can execute when the user opens it in a browser. The command-line `strat` value is also used directly when constructing input and output filenames. It ...[truncated 1993 chars]- Remediation
View remediation
1 else "golden_cross" if strat not in ALLOWED_STRATEGIES: raise ValueError(f"Unsupported strategy: {strat!r}") ``` 2. Escape every textual value inserted into HTML, not only selected fields: ```python def esc(value): return html.escape(str(value), quote=True) q_rows += ( f"{esc(k)}{esc(v)}" f"" ) ``` 3. Apply the same escaping to `date_range`, quarter labels, and every other string obtained from JSON. 4. Validate loaded JSON against a strict schema. Require numeric fields to be finite numbers and textual fields to follow expected formats. 5. Use `pathlib.Path` and verify that resolved input and output paths remain under `BASE`: ```python base = Path(BASE).resolve() output = (base / f"full_attribution_report_{strat}.html").resolve() if output.parent != base: raise ValueError("Output path escapes the report directory") ``` 6. Prefer a template engine with automatic HTML escaping rather than assembling large HTML documents through direct f-string interpolation. 7. If reports may contain untrusted data, add a restrictive Content Security Policy that blocks inline scripts and unnecessary network connections. This should be defense in depth and not a substitute for output escaping. ]]>
