T09 · Insecure Skill Coding Practices
- Location
scripts/render_dashboard.py:236- Finding
Stored XSS Through Unescaped JSON Embedded in a Script Element
- Content
View full analysis
{payload_json} ``` ### Technical Analysis The dashboard generator serializes resume data with `json.dumps()` and directly embeds the result in an HTML ``. Consequently, attacker-controlled resume content containing a payload such as the following can terminate the JSON data element and introduce a new executable script: ```html ``` The affected payload includes `onepage_md`, project-label statistics, gaps, and the generation timestamp. The resume and derived fields originate from files that may contain user-provided or third-party-provided content. The fact that the script element uses `type="application/json"` does not mitigate the issue: the HTML parser recognizes the closing `` sequence before JavaScript or JSON parsing occurs. ### Attack Path 1. An attacker supplies a crafted resume, work log, project label, or gap value. 2. The malicious value is propagated into the dashboard payload. 3. `_render_html()` serializes the value through `json.dumps()` without HTML-safe escaping. 4. The serialized payload is inserted directly into the `resumeData` script element. 5. The user opens `resume-dashboard.html`, or `export_pdf.py` loads it through Playwright. 6. The injected closing tag terminates the data element, and the attacker's new script executes in the dashboard's browser context. ### Impact Assessment Successful exploitation permits attacker-controlled JavaScript execution in the local dashboard page and in the headless ...[truncated 660 chars]- Remediation
View remediation
` as `\u003e` - `&` as `\u0026` - U+2028 as `\u2028` - U+2029 as `\u2029` 3. Prefer writing the payload to a separate local JSON file and loading it as data rather than embedding it in HTML. 4. Add a restrictive Content Security Policy that disallows inline scripts and limits network destinations. 5. Add regression tests containing ``, HTML tags, event handlers, and Unicode separator characters. 6. Treat all resume, work-log, project-label, and gap content as untrusted input regardless of whether it comes from a local file. ]]>
