T09 · Insecure Skill Coding Practices
- Location
scripts/build_report_html.py:895- Finding
Unsafe Markdown Link Schemes Permit JavaScript Execution in Generated Reports
- Content
View full analysis
{escape(match.group(1))}', ) ``` ### Technical Analysis The Markdown renderer places a user-controlled link destination directly into an HTML `href` attribute. Although `escape(..., quote=True)` prevents HTML attribute breakout, it does not validate the URI scheme. Consequently, dangerous schemes such as `javascript:`, `data:`, `vbscript:`, or `file:` can survive HTML rendering. For example, the following Markdown contains a JavaScript URL that does not require parentheses: ```markdown [Open report details](javascript:document.body.textContent='Report modified') ``` It is rendered as: ```html Open report details ``` When a reader clicks the link, the browser evaluates the JavaScript in the generated report's document context. This is a scheme-validation flaw rather than an HTML-escaping flaw: encoding special characters does not neutralize a syntactically valid dangerous URI. The vulnerable data flow is: 1. Markdown is read from a file under the report's `sections/` directory. 2. `render_markdown()` processes the section. 3. `render_inline()` recognizes Markdown links. 4. The destination is HTML-escaped but not parsed or allowlisted. 5. The resulting unsafe link is written to `dist/report.html`. ### Attack Path 1. An attacker causes crafted Markdown to be included in a report section. This may occur through externally supplied report content, chart-related text incorporated into a generated section, or modification of a section file before report generation. 2. The attacker includes a link with a dangerous destination, such ...[truncated 1331 chars]- Remediation
View remediation
str | None: value = raw.strip() if any(ord(char) < 0x20 or ord(char) == 0x7F for char in value): return None parsed = urlsplit(value) if parsed.scheme and parsed.scheme.lower() not in ALLOWED_SCHEMES: return None if value.startswith("//"): return None return value ``` The renderer should emit a normal anchor only when `safe_href()` returns a value; otherwise, it should render the label as escaped plain text. ]]>
