T09 · Insecure Skill Coding Practices
- Location
scripts/generate_visual.py:382- Finding
Stored HTML Injection Through Unvalidated Checklist Status
- Content
View full analysis
{_h(c.get('text', ''))} {_h(status)}\n" template = template.replace('{{checklist}}', checklist) ``` ### Technical Analysis The `checklist[].status` value originates from summary JSON generated from session content. Although `_h(status)` escapes the value rendered as element text, the same `status` value is inserted directly into the quoted `class` attribute without validation or attribute encoding: ```python class=\"status {status}\" ``` An attacker-controlled value containing a quotation mark can terminate the `class` attribute and inject additional attributes or elements. For example, a value shaped like the following could introduce an event handler: ```text ">- Remediation
View remediation
{_h(c.get("text", ""))} ' f'{_h(status)}\n' ) ``` 2. Validate the complete model response against a strict JSON schema before rendering. Reject or normalize incorrect types, unknown status values, excessive collection sizes, and excessively long strings. 3. Use a context-aware templating engine with automatic HTML attribute and text escaping rather than assembling HTML with formatted strings. 4. Add a restrictive Content Security Policy to generated HTML. Where practical, move the legitimate inline script to a separate local asset and use a policy similar to: ```text default-src 'none'; script-src 'self'; style-src 'unsafe-inline'; img-src data:; connect-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'; ``` If the export must remain a single file, use a nonce or hash for the known inline script instead of allowing arbitrary inline execution. 5. Treat all model-generated output as untrusted, even when the prompt specifies an exact enumeration. 6. Before loading generated HTML in Playwright, perform schema validation and consider disabling unnecessary browser capabilities and outbound networking in the screenshot environment. ]]>
