T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/render_cards.py:341
- Finding
- Arbitrary HTML and JavaScript Injection Through Raw Headline Fields<![CDATA[ ## Vulnerability Details **File Location**: `scripts/render_cards.py:341` and `scripts/render_cards.py:398-400` **Vulnerability Type**: Untrusted HTML injection in generated browser content **Risk Level**: High ### Vulnerable Code ```python def title(self, fs): return '<h1 style="font-size:%dpx">%s</h1>' % ( fs, self.c.get("headline_html") or esc(self.c.get("headline", "")) ) ``` ```python head = self.c.get("banner_headline_html") or ( esc(self.c.get("headline", "")) + ' <em>· ' + esc(self.c.get("banner_suffix", "")) + '</em>' if self.c.get("banner_suffix") else esc(self.c.get("headline", "")) ) ``` The generated page is subsequently opened in headless Chrome: ```python cmd = [ chrome, "--headless", "--disable-gpu", "--hide-scrollbars", "--force-device-scale-factor=%d" % args.scale, "--virtual-time-budget=3000", "--window-size=%d,%d" % (f["w"], f["h"]), "--screenshot=" + png_path, "file:///" + html_path.replace("\\", "/"), ] proc = subprocess.run(cmd, capture_output=True, text=True, timeout=180) ``` ### Technical Analysis Most configuration text is processed by `esc()`, but the `headline_html` and `banner_headline_html` configuration properties bypass escaping and are inserted verbatim into an HTML document. Because the generated document is loaded by a full headless browser, these properties can contain active markup such as `<script>` elements or event handlers. The Chrome invocation does not disable JavaScript or network connectivity. Consequently, rendering an untrusted configuration can execute attacker-controlled JavaScript in the browser context. This is not equivalent to direct native command execution, but injected JavaScript can access the generated document, including the Base64-embedded proof image, and can attempt outbound requests or browser-based interactions with services reachable from the host. ### Attack Path 1. An attacker supplies or influences a ce ...[truncated 1709 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove `headline_html` and `banner_headline_html` if raw HTML is not essential. 2. Represent formatting through structured configuration rather than executable markup, such as separate plain-text and emphasis fields. 3. If limited HTML must be supported, sanitize it with a strict allowlist that permits only required formatting elements such as `<em>` and rejects: - `<script>`, `<iframe>`, `<object>`, and `<embed>` - Event-handler attributes such as `onload` and `onerror` - URLs and unsafe attributes - SVG and MathML active content 4. Escape all text nodes and attribute values according to their HTML context. 5. Consider disabling JavaScript for the screenshot process if the layout does not require it. The current fit pass uses JavaScript, so replacing it with a trusted static mechanism or isolated preprocessing would be necessary first. 6. Run the renderer in a sandbox with restricted network access when processing configurations from untrusted sources. 7. Add regression tests using script tags, event handlers, malformed HTML, SVG payloads, and encoded injection variants. ]]>
