T09 · Insecure Skill Coding Practices
Error
- Location
- web/index.html:1607
- Finding
- Stored DOM Cross-Site Scripting Through Unsanitized Report Content and Metadata<![CDATA[ ## Vulnerability Details **File Location**: `web/index.html:1488-1501`, `web/index.html:1557-1609`, `web/index.html:1720-1800`, and `scripts/report_indexer.py:246-260` **Vulnerability Type**: Stored DOM cross-site scripting **Risk Level**: High ### Vulnerable Code The report body is transformed by a custom Markdown parser and assigned directly to `innerHTML`: ```javascript // web/index.html:1607-1609 const mdSurface = document.getElementById('reportMarkdownBody'); mdSurface.innerHTML = parseAdvancedMarkdown(data.body_markdown || data.raw_content); ``` The custom parser does not escape ordinary HTML or sanitize the generated output: ```javascript // web/index.html:1720-1800 function parseAdvancedMarkdown(md) { if (!md) return ''; let text = md; // 1. Code blocks with copy button text = text.replace(/```([a-zA-Z0-9_-]*)\n([\s\S]*?)```/gm, (match, lang, code) => { const escaped = escapeHtml(code); return ` <div class="code-block-wrapper"> <div class="code-block-header"> <span>${lang || 'text'}</span> <button class="code-copy-btn" aria-label="复制代码块" onclick="copySnippet(this)" data-code="${encodeURIComponent(code)}">复制</button> </div> <pre><code class="lang-${lang}">${escaped}</code></pre> </div> `; }); // 2. Callout Cards text = text.replace(/^\>\s+\[!(NOTE|TIP|WARNING|IMPORTANT|CAUTION)\]\s*\n((?:\>.*(?:\n|$))*)/gim, (m, type, body) => { const cleanBody = body.replace(/^\>\s?/gm, '').trim(); const typeLower = type.toLowerCase(); let icon = 'ℹ️'; if (typeLower === 'tip') icon = '💡'; else if (typeLower === 'warning') icon = '⚠️'; else if (typeLower === 'important') icon = '⚡'; else if (typeLower === 'caution') icon = '🛑'; return ` <div class="callout-card ${typeLower}"> <div class="callout-header"> <span>${icon}</span> <span>${type}</span> </div> <div>${parseInlineMarkdown(cleanBody)} ...[truncated 5069 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace the custom parser with a maintained Markdown library configured to reject or escape raw HTML. 2. Sanitize all rendered HTML using a strict allowlist sanitizer such as DOMPurify before assigning it to the DOM. 3. Prefer a configuration that disables raw HTML completely unless it is explicitly required. 4. Render metadata using `textContent`, `createElement()`, and `setAttribute()` rather than interpolating values into HTML strings. 5. Remove inline `onclick` handlers and register handlers with `addEventListener()`. 6. Pass report paths through JavaScript closures or `data-*` properties rather than embedding them in executable JavaScript. 7. Validate frontmatter fields such as `code`, `category`, `rating`, and dates against explicit formats. 8. Add a restrictive Content Security Policy that disallows inline scripts and event handlers. 9. Add regression tests covering: - `<img src=x onerror=...>` - `<svg onload=...>` - Malicious frontmatter values - Apostrophes and quotes in report filenames - Nested HTML in tables, headings, and callouts ]]>
