T09 · Insecure Skill Coding Practices
- Location
scripts/report_generator.py:113- Finding
Stored HTML and JavaScript Injection in Generated Reports
- Content
View full analysis
Vulnerability Details
File Location:
scripts/report_generator.py, lines 113-163
Vulnerability Type: Unescaped HTML generation from attacker-controlled report configuration and data
Risk Level: MediumVulnerable Code
python body = f"<h1>{title}</h1>\n" if metadata: body += f"<p class='meta'>生成时间: {metadata.get('generated_at', datetime.now().strftime('%Y-%m-%d %H:%M'))}</p>\n" if metadata.get("period"): body += f"<p class='meta'>数据周期: {metadata['period']}</p>\n" for section in sections: body += f"<h2>{section['title']}</h2>\n" content = section.get("content", "") if isinstance(content, dict): # KPI 卡片 if all(isinstance(v, dict) and "value" in v for v in content.values()): for k, v in content.items(): body += f"<div class='kpi'><div class='value'>{v.get('value', 'N/A')}</div><div class='label'>{k}</div></div>\n" else: body += _dict_to_html_table(content) elif isinstance(content, list) and content and isinstance(content[0], dict): body += _list_to_html_table(content) else: body += f"<p>{content}</p>\n" if section.get("insight"): body += f"<div class='insight'>💡 <strong>洞察</strong>: {section['insight']}</div>\n" html = f"""<!DOCTYPE html> <html lang="zh-CN"><head><meta charset="utf-8"><title>{title}</title><style>{css}</style></head> <body>{body}</body></html>""" def _dict_to_html_table(d: dict) -> str: rows = "" if all(isinstance(v, dict) for v in d.values()): sub_keys = list(dict.fromkeys(k for v in d.values() for k in v.keys())) rows += "<tr><th>指标</th>" + "".join(f"<th>{k}</th>" for k in sub_keys) + "</tr>" for k, v in d.items(): rows += "<tr><td>" + k + "</td>" + "".join(f"<td>{v.get(sk, '')}</td>" for sk in sub_keys) + "</tr>" else: for k, v in d.items(): rows += f"<tr><td>{k}</td><td>{v}</td></tr>" return f"<table>{rows}</table>" de ...[truncated 2490 chars]- Remediation
View remediation
Remediation Suggestions
- Escape every dynamic value before inserting it into HTML. Use
html.escape(str(value), quote=True)for report titles, metadata, section titles, content, insights, KPI fields, table keys, headers, and cells. - Prefer a template engine with automatic HTML escaping enabled rather than constructing markup through string interpolation.
- If rich HTML content is an intentional feature, sanitize it with a strict allowlist-based HTML sanitizer. Remove scripts, event-handler attributes, active embedded elements, unsafe URL schemes, and dangerous CSS.
- Apply context-appropriate escaping, including HTML text escaping and HTML attribute escaping where applicable.
- Add a restrictive Content Security Policy when reports are served, for example by disallowing inline scripts and limiting external connections. This should be defense in depth rather than a substitute for escaping.
- Add regression tests using payloads in every dynamic field, including:
<script>alert(1)</script><img src=x onerror=alert(1)><svg onload=alert(1)>- malformed markup intended to escape table or paragraph contexts
- Consider opening generated reports under an isolated origin or sandboxing them when they contain data from untrusted sources.
- Escape every dynamic value before inserting it into HTML. Use
