T09 · Insecure Skill Coding Practices
- Location
generator/html_generator.py:571- Finding
Untrusted document content is rendered as active HTML and executed by Playwright
- Content
View full analysis
str: headers = data.get("headers", []) rows = data.get("rows", []) hdr_html = "".join(f"{h}" for h in headers) rows_html = "".join("" + "".join(f"{c}" for c in row) + "\n" for row in rows) return f'\n{hdr_html}{rows_html}\n\n' ``` The generated document also interpolates an unescaped title: ```python return f""" {title} :root {{ {css_vars} }} {STYLE}{header_html} {sections_html} {footer_html}""" ``` The resulting attacker-influenced file is then loaded with JavaScript enabled: ```python html_abs = os.path.abspath(html_path) html_url = f"file:///{html_abs.replace(chr(92), '/')}" with sync_playwright() as p: b = p.chromium.launch(headless=True) page = b.new_page(viewport={"width": 1280, "height": 900}) page.goto(html_url, wait_until="networkidle") ``` ### Technical Analysis Document and spreadsheet values are treated as trusted markup. For example, CSV, Excel, Word, and PDF-derived table cells flow into `build_table()`, where they are concatenated directly into `` and `` elements without HTML escaping. The same unsafe interpolation pattern exists in other rendering helpers, including header, timeline, comparison, SWOT, four-dimensional analysis, source statistics, interview, and section-header rendering. Some values are also inserted into HTML attributes without a ...[truncated 2511 chars]- Remediation
View remediation
str: return escape(str(value if value is not None else ""), quote=True) hdr_html = "".join(f"{text(h)}" for h in headers) rows_html = "".join( "" + "".join(f"{text(c)}" for c in row) + "\n" for row in rows ) ``` 3. Apply the same protection to all renderer functions, especially: - `generate_html()` - `build_header()` - `build_sections()` - `build_timeline()` - `build_compare()` - `build_swot()` - `build_four_dim()` - `build_source_stats()` - `build_interview()` 4. Add defense in depth to the exporter: - Create the browser context with JavaScript disabled if the dashboard does not require scripts. - Intercept and abort all non-`file` or nonessential requests. - Run Chromium in a sandboxed, low-privilege container with no credentials or sensitive mounted files. - Impose navigation, rendering, file-size, page-count, and execution time limits. 5. Add a restrictive Content Security Policy, for example one that denies scripts, network connections, frames, objects, and remote resources: ```html ``` 6. Add regression tests using payloads in every supported format and every rendered field. Tests should verify that payloads appear as literal text and that the exporter makes no external or internal netwo ...[truncated 18 chars]
