T09 · Insecure Skill Coding Practices
Error
- Location
- viewer/generate_review.py:271
- Finding
- Stored Script Injection Through Unsafe Embedding of Evaluation Data<![CDATA[ ## Vulnerability Details **File Location**: `viewer/generate_review.py:271-275`; injection sink in `viewer/viewer.html:647-650` **Vulnerability Type**: Stored cross-site scripting through unsafe JavaScript serialization **Risk Level**: High ### Vulnerable Code ```python data_json = json.dumps(embedded) return template.replace( "/*__EMBEDDED_DATA__*/", f"const EMBEDDED_DATA = {data_json};", ) ``` The generated value is inserted directly into an executable script block: ```html <script> // ---- Embedded data (injected by generate_review.py) ---- /*__EMBEDDED_DATA__*/ ``` ### Technical Analysis The generator serializes workspace-controlled data with `json.dumps()` and inserts the resulting JSON directly into an HTML `<script>` element. JSON serialization escapes JavaScript string delimiters, but it does not make the value safe for an HTML script-data context. In particular, an embedded value containing a sequence such as: ```html </script><script>/* attacker-controlled JavaScript */</script> ``` can terminate the original script element before the JavaScript parser processes the JSON string. The browser then interprets the injected markup as a new executable script. Potentially attacker-controlled embedded fields include: - Evaluation prompts - Generated output files - Grading records - Previous feedback and outputs - Benchmark content - Skill names Evaluation output is especially untrusted because an evaluated Skill or model can deliberately produce the breakout sequence. ### Attack Path 1. An attacker creates or influences an evaluated Skill, prompt, output, grading record, or benchmark. 2. The attacker causes one of the embedded text fields to contain a `</script>` breakout followed by an attacker-controlled script element. 3. A reviewer runs `viewer/generate_review.py` against the affected evaluation workspace. 4. `generate_html()` inserts the serialized data into the executable script block without HTML-context escaping. 5. ...[truncated 1196 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not place raw JSON directly in an executable script element. 2. Store serialized data in a non-executable element: ```html <script id="embedded-data" type="application/json"> SAFE_SERIALIZED_DATA </script> ``` 3. Before insertion, escape all characters that can affect the HTML parser, including `<`, `>`, `&`, U+2028, and U+2029. At minimum, replace `<` with `\u003c`. 4. Parse the value from text rather than executing it: ```javascript const EMBEDDED_DATA = JSON.parse( document.getElementById("embedded-data").textContent ); ``` 5. Prefer a vetted serializer designed for embedding JSON in HTML. 6. Add a restrictive Content Security Policy, such as a nonce-based `script-src`, and remove inline event handlers and inline scripts. 7. Add regression tests containing `</script>`, HTML tags, quotes, Unicode separators, and script payloads in every embedded field. 8. Treat all evaluation artifacts as untrusted, even when they were generated locally. ]]>
