T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/generate_report.py:196
- Finding
- Stored Cross-Site Scripting in Generated HTML Reports<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_report.py:196, 233, 280, 489, 529, 636-641` **Vulnerability Type**: Stored cross-site scripting through unsafe HTML and JavaScript embedding **Risk Level**: High ### Vulnerable Code ```python # Category values are inserted directly into HTML. for cat, data in sorted(stats['categories'].items(), key=lambda x: -x[1]['total']): rows += f''' <tr> <td class="cat-name">{cat}</td> ``` ```python # Findings are serialized directly into an executable script context. findings_json = json.dumps(findings, ensure_ascii=False) ``` ```python # The project name is inserted directly into multiple HTML contexts. <title>{title_text} - {project_name}</title> ``` ```python <div class="meta">{project_name} · <span data-i18n="generated">{generated_text}</span> {now}</div> ``` ```javascript // JSON containing untrusted finding fields is embedded in a normal script. const findings = {findings_json}; ``` ```javascript // File, category, and type values are not escaped before assignment to innerHTML. div.innerHTML = sevTag + '<div class="finding-content">' + '<div class="finding-message">' + escapeHtml(f.message || noDesc) + '</div>' + '<div class="finding-meta">' + metaParts.join(' | ') + '</div>' + snippet + '</div>'; ``` ### Technical Analysis The report generator processes findings loaded from JSON files, standard input, or inline JSON. These findings may contain data derived from an untrusted repository, including source-code snippets and file paths. Crafted JSON input can additionally control fields such as `category`, `type`, and `message`. Calling `json.dumps()` does not make a value safe for direct placement inside an HTML `<script>` element. For example, an attacker-controlled finding containing a sequence such as: ```html </script><script>alert(document.domain)</script> ``` can terminate the original script element b ...[truncated 2903 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Remove dynamic `innerHTML` construction** - Create report elements with `document.createElement()`. - Assign all untrusted values through `textContent`. - Use `appendChild()` or `replaceChildren()` rather than HTML string concatenation. 2. **Safely transport findings into JavaScript** - Prefer a non-executable data element such as: ```html <script id="findings-data" type="application/json">...</script> ``` - Before embedding serialized JSON in HTML, escape at least `<` as `\u003c` so `</script>` cannot terminate the element. - Parse the element's `textContent` with `JSON.parse()`. - Alternatively, store the data in a separate JSON file when a self-contained report is not required. 3. **Apply context-appropriate server-side escaping** - Escape `project_name` before inserting it into the title and visible header. - Escape category names before inserting them into table HTML. - Do not rely on one generic escaping routine for HTML text, HTML attributes, URLs, and JavaScript contexts. 4. **Validate input structure** - Require every finding to match a strict schema. - Restrict severity to known values. - Normalize scalar fields to strings and reject nested objects where strings are expected. - Apply reasonable length limits to findings, snippets, paths, categories, and project names. 5. **Add defense in depth** - Add a restrictive Content Security Policy that blocks inline and remote scripts. If inline JavaScript remains necessary, use a nonce or hash. - Avoid loading remote resources in generated reports. - Document that findings files and repositories may be attacker-controlled. 6. **Add regression tests** Test every rendered field with payloads containing: ```text </script><script>alert(1)</script> <img src=x onerror=alert(1)> " ' < > & </style> ``` Tests should generate the report, open or parse it with a browser-capable test fram ...[truncated 103 chars]
