CASE FILE#7161WARNFiled 2026-04-13

Preventing XSS: VS Code Copilot and dangerouslySetInnerHTML

VS Code Copilot uses React's dangerouslySetInnerHTML to render user-generated content. SSG flags the unsafe pattern before it's saved — DOM-based XSS from unescaped HTML is a critical web security risk.

Case ID
#7161
Severity
WARN
Decision
BLOCK
Agent
VS Code
Category
Source Code

Correction note (2026-10-13). The per-call timings and latency figures that appeared in this article had no benchmark behind them and were removed. Sample output in this article is illustrative, not a recorded run. The only published measurement is p50 0.39 ms and p99 1.91 ms (sigmashake-bench daemon-socket run, 2026-06-10, ssg 0.29.156, n=500). Sub-2 ms evaluation is a design target.

Describe the task

VS Code Copilot is rendering a user-authored blog post preview. It uses React's escape hatch to inject HTML directly into the DOM:

<div dangerouslySetInnerHTML={{ __html: userPost.content }} />

SSG catches the write before the file is saved — unsanitized dangerouslySetInnerHTML is a direct XSS vector.

# illustrative sample output
[BLOCK] write › src/components/PostPreview.tsx — rule: no-dangerous-inner-html

Give SSG context

SSG evaluates VS Code Copilot's file write calls via the SSG MCP Server integration.

Required context

rule no-dangerous-inner-html {
  enabled true
  priority 100
  severity error
  DENY write
  IF content CONTAINS "dangerouslySetInnerHTML"
  MESSAGE "dangerouslySetInnerHTML detected. Sanitize with DOMPurify or use a safe markdown renderer."
}

Optional context

Also flag innerHTML direct assignment in non-React code:

rule no-raw-innerhtml {
  enabled true
  priority 90
  severity error
  DENY write
  IF path MATCHES ".*\.(ts|tsx|js|jsx)$"
  AND content CONTAINS ".innerHTML ="
  MESSAGE "Direct innerHTML assignment is a potential XSS vector. Use textContent or a safe renderer."
}

What SSG does

SSG blocks the write call before the file is modified on disk. The unsafe pattern never enters your codebase — no sanitization step is needed retroactively.

Ask the agent to sanitize first

dangerouslySetInnerHTML was blocked. Safer alternatives:
  1. Use DOMPurify: import DOMPurify from 'dompurify';
     <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(content) }} />
  2. Use a safe markdown renderer (react-markdown) that doesn't allow raw HTML
  3. Use textContent-based rendering for plain text

Allowlist known-safe usage

If you use a trusted sanitizer in a specific component, allowlist it:

rule allow-dompurify-html {
  enabled true
  priority 200
  severity info
  ALLOW write
  IF content CONTAINS "dangerouslySetInnerHTML"
  AND content CONTAINS "DOMPurify.sanitize"
  MESSAGE "Allowed: the HTML is sanitized with DOMPurify before injection."
}

Test your sanitizer with an XSS probe

Before shipping any HTML rendering code, test with: <img src=x onerror=alert(1)> — if the alert fires, your sanitizer is not working correctly.

Filed by VS Code
Engine ssg v1 · 2026-04-13
End of case file

Stop reading. Start governing.

Test a rule against any tool call right now. No install required.