- Case ID
- #6347
- Severity
- WARN
- Decision
- BLOCK
- Agent
- OpenHands
- 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
You ask OpenHands to render some user-generated HTML content in a React component. The agent uses the React escape hatch for raw HTML injection:
function UserPost({ content }: { content: string }) {
return <div dangerouslySetInnerHTML={{ __html: content }} />;
}
If content is user-supplied and not sanitized, an attacker can inject a script tag and execute arbitrary JavaScript in your users' browsers — stealing sessions, redirecting to phishing pages, or exfiltrating data. SSG's no-dangerous-inner-html rule flags the write.
# illustrative sample output
[BLOCK] write_file › src/components/UserPost.tsx — rule: no-dangerous-inner-html
Reason: dangerouslySetInnerHTML with a variable source detected.
Give SSG context
SSG intercepts write calls via the SSG MCP Server integration for OpenHands agents and validates component code before saving.
Required context
rule no-dangerous-inner-html {
enabled true
priority 90
severity error
DENY write
IF content CONTAINS "dangerouslySetInnerHTML"
AND content CONTAINS "__html:"
AND content NOT CONTAINS "DOMPurify"
AND content NOT CONTAINS "sanitize"
MESSAGE "dangerouslySetInnerHTML without sanitization is an XSS risk. Use DOMPurify or a safe renderer."
}
Optional context
The rule allows the pattern when DOMPurify is already imported in the same file. If your team uses a different sanitization library, add it to the exclusion:
rule no-dangerous-inner-html-custom-sanitizer {
enabled true
priority 90
severity error
DENY write
IF content CONTAINS "dangerouslySetInnerHTML"
AND content CONTAINS "__html:"
AND content NOT CONTAINS "DOMPurify"
AND content NOT CONTAINS "sanitize"
AND content NOT CONTAINS "sanitizeHtml"
AND content NOT CONTAINS "xss("
MESSAGE "dangerouslySetInnerHTML without sanitization is an XSS risk. Use DOMPurify or a safe renderer."
}
What SSG does
SSG checks for the presence of dangerouslySetInnerHTML alongside a variable source and the absence of a sanitizer reference. Files that import and use DOMPurify before passing to __html will pass this check.
Ask the agent to add sanitization
dangerouslySetInnerHTML was blocked: the content source is not sanitized.
Rewrite using DOMPurify:
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(content) }} />
Or use a safe Markdown renderer like react-markdown instead of raw HTML.
Suggest a Markdown renderer as the correct approach
For most user-generated content, Markdown rendering is safer than raw HTML:
If the content is Markdown, use react-markdown:
import ReactMarkdown from 'react-markdown';
<ReactMarkdown>{content}</ReactMarkdown>
This renders safe HTML without exposing you to injection.
Audit all dangerouslySetInnerHTML uses in your codebase
Run grep -r "dangerouslySetInnerHTML" src/ after onboarding SSG to find historical uses that predate the rule. Address those before new vulnerabilities are introduced.
How your rule avoids false positives
The condition AND content NOT CONTAINS "DOMPurify" passes the check if DOMPurify is imported anywhere in the file — even if it's not on the same line as the dangerouslySetInnerHTML call. For stricter enforcement, require the sanitize call to be adjacent to the __html assignment.
Check the rule against your test files
Test files may render unsanitized HTML intentionally to test XSS scenarios. Add a path exclusion for *.test.tsx or *.spec.tsx if your tests legitimately use the unsafe pattern.