T09 · Insecure Skill Coding Practices
- Location
eval-viewer/generate_review.py:259- Finding
Stored Script Injection Through Embedded Evaluation Data
- Content
View full analysis
str: """Generate the complete standalone HTML page with embedded data.""" template_path = Path(__file__).parent / "viewer.html" template = template_path.read_text() # Build previous_feedback and previous_outputs maps for the template previous_feedback: dict[str, str] = {} previous_outputs: dict[str, list[dict]] = {} if previous: for run_id, data in previous.items(): if data.get("feedback"): previous_feedback[run_id] = data["feedback"] if data.get("outputs"): previous_outputs[run_id] = data["outputs"] embedded = { "skill_name": skill_name, "runs": runs, "previous_feedback": previous_feedback, "previous_outputs": previous_outputs, } if benchmark: embedded["benchmark"] = benchmark data_json = json.dumps(embedded) return template.replace( "/*__EMBEDDED_DATA__*/", f"const EMBEDDED_DATA = {data_json};" ) ``` The resulting data is inserted into this executable script context: ```html- Remediation
View remediation
__SAFELY_ENCODED_JSON__ ``` 3. Before inserting JSON into HTML, escape characters significant to the HTML parser: ```python data_json = json.dumps(embedded, ensure_ascii=False) data_json = ( data_json .replace("&", "\\u0026") .replace("<", "\\u003c") .replace(">", "\\u003e") .replace("\u2028", "\\u2028") .replace("\u2029", "\\u2029") ) ``` 4. Prefer serving JSON through a dedicated authenticated endpoint rather than embedding all potentially sensitive outputs in the HTML. 5. Add a restrictive Content Security Policy that disallows inline and untrusted scripts. Use nonces or hashes for required local scripts. 6. Add regression tests containing ``, HTML tags, quotes, Unicode separators, and event-handler payloads in every embedded text field. 7. Treat all generated skill outputs as untrusted, even when the viewer is only bound to loopback. ]]>
