T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/generate_html.py:11
- Finding
- Stored Script Injection in Generated Mind Map HTML<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_html.py:11-12, 21, 65` **Vulnerability Type**: Stored script injection caused by unsafe HTML and JavaScript embedding **Risk Level**: High ### Vulnerable Code ```python workspace_title = data.get("t", "Notion Mind Map") json_str = json.dumps(data, ensure_ascii=False, separators=(',', ':')) html = ( '<!DOCTYPE html>\n' '<html lang="zh-CN">\n' '<head>\n' '<meta charset="UTF-8">\n' '<meta name="viewport" content="width=device-width, initial-scale=1.0">\n' '<title>' + workspace_title + ' - 思维导图</title>\n' # ... '<script>\n' '"use strict";\n' 'const RAW = ' + json_str + ';\n' ) ``` The embedded values originate from the supplied HTML file. For example, the workspace title is extracted without output encoding: ```python def extract_workspace_name_from_html(soup, content): match = re.search(r'工作空间名称[::]\s*(.+?)(?:</p>|<li>|$)', content) if match: return match.group(1).strip() title = soup.find('title') if title: t = title.get_text().strip() t = re.sub(r'^Export[-_]?\s*', '', t, flags=re.IGNORECASE) return t or "Notion" return "Notion" ``` ### Technical Analysis The generated document directly concatenates an untrusted workspace title into the HTML `<title>` element. It also serializes the complete attacker-influenced mind-map data as JSON and places it directly inside an executable `<script>` element. `json.dumps()` produces valid JSON, but it does not make the result safe for inclusion in an HTML script element. In HTML parsing, a literal `</script>` sequence terminates the script element even when that sequence occurs inside a JavaScript string. Consequently, a malicious title containing a sequence such as `</script><script>/* attacker code */</script>` can escape the data block and introduce executable JavaScript. The separate insertion into `<title>` is also unsafe. A value containing `</title> ...[truncated 1412 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. HTML-escape the workspace title before inserting it into the `<title>` element: ```python import html safe_workspace_title = html.escape(workspace_title, quote=True) ``` 2. Do not concatenate ordinary JSON directly into an executable script element. Store it in a non-executable JSON element and escape characters significant to HTML parsing: ```python json_str = json.dumps(data, ensure_ascii=False, separators=(',', ':')) json_str = ( json_str .replace('&', '\\u0026') .replace('<', '\\u003c') .replace('>', '\\u003e') .replace('\u2028', '\\u2028') .replace('\u2029', '\\u2029') ) ``` Then embed and parse it as data: ```html <script id="mindmap-data" type="application/json">...</script> <script> const RAW = JSON.parse(document.getElementById("mindmap-data").textContent); </script> ``` 3. Prefer DOM APIs such as `textContent` whenever untrusted values are rendered into HTML. 4. Add a restrictive Content Security Policy to limit the impact of any remaining injection issue. Moving JavaScript to a separate local file would allow inline scripts to be disabled. 5. Add regression tests containing values such as: ```text </title><script>alert(1)</script> </script><script>alert(1)</script> <>&"' and Unicode line separators ``` The tests should verify that these strings remain inert text in the generated document. ]]>
