T09 · Insecure Skill Coding Practices
- Location
scripts/templates/ymindmap.html:676- Finding
Stored Script Injection in Generated Graph Pages
- Content
View full analysis
str: """Inject graph data (and optional chat messages) into the HTML template.""" title = "" if "meta" in graph_json and graph_json["meta"]: title = graph_json["meta"].get("title", "") html = template.replace("{{TITLE}}", title or "Untitled") html = html.replace("{{GRAPH_JSON}}", json.dumps(graph_json, ensure_ascii=False)) chat_json_str = json.dumps(chat_messages, ensure_ascii=False) if chat_messages is not None else "null" html = html.replace("{{CHAT_JSON}}", chat_json_str) return html ``` The resulting values are inserted directly into executable HTML: ```html ` terminates the script element even if it appears inside a JavaScript or JSON string. Consequently, a graph title, node field, summary, source field, or raw chat message containing a payload such as: ```html ``` can terminate the intended script and create a new executable script element. The title substitution is independently unsafe because it is inserted into the `` element wi ...[truncated 2618 chars]- Remediation
View remediation
` element. 2. Store data in non-executable JSON elements: ```html ``` 3. Before substitution, perform HTML-safe JSON serialization by escaping at least `<`, `>`, `&`, U+2028, and U+2029: ```python def html_safe_json(value): return ( json.dumps(value, ensure_ascii=False) .replace("&", "\\u0026") .replace("<", "\\u003c") .replace(">", "\\u003e") .replace("\u2028", "\\u2028") .replace("\u2029", "\\u2029") ) ``` 4. Parse the non-executable JSON explicitly: ```javascript const __YMIND_DATA__ = JSON.parse(document.getElementById('ymind-data').textContent); ``` 5. HTML-escape the title before inserting it into ``, or set `document.title` through a trusted static bootstrap script using parsed data. 6. Add a restrictive Content Security Policy. Prefer a local, hashed bootstrap script and disallow inline execution: ```html <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; connect-src 'none'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'"> ``` 7. Avoid serving the whole run directory solely to capture a screenshot. Serve only the required HTML and static assets through a handler that denies directory listing and access to JSON source files. 8. Add regression tests using payloads containing `</script>`, ``, HTML attributes, Unicode separators, and ampersands. ]]>
