T09 · Insecure Skill Coding Practices
- Location
web/index.html:1608- Finding
Stored Cross-Site Scripting in Markdown Report Rendering
- Content
View full analysis
Vulnerability Details
File Location:
web/index.html:1608-1609, with the unsafe parser atweb/index.html:1716-1794
Vulnerability Type: Stored Cross-Site Scripting (XSS)
Risk Level: HighVulnerable Code
javascript // Render Markdown content const mdSurface = document.getElementById('reportMarkdownBody'); mdSurface.innerHTML = parseAdvancedMarkdown(data.body_markdown || data.raw_content);The report content is processed by a custom Markdown parser that does not escape raw HTML:
javascript 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)}</div> </div> `; }); // 3. Regular Blockquotes text = text.replace(/^\>\s+(.*$)/gim, '<blockquote>$1</blockquote>'); // 4. Headers text = text.repl ...[truncated 4086 chars]- Remediation
View remediation
Remediation Suggestions
- Replace the custom Markdown implementation with a maintained renderer configured to disable raw HTML.
- Sanitize all generated HTML with a strict allowlist before assigning it to
innerHTML. - Remove event-handler attributes, scripts, dangerous URL schemes, embedded frames, and other active content.
- Prefer DOM construction and
textContentfor report metadata and other plain-text fields. - Avoid inline event handlers in application-generated markup. Register handlers with
addEventListenerinstead. - Deploy a restrictive Content Security Policy that blocks inline scripts and event handlers as defense in depth.
- Add regression tests containing script elements, event-handler attributes, SVG-based payloads, malformed markup, and dangerous links.
- Treat every report as untrusted unless its provenance and integrity are explicitly verified.
