Finding a Stored XSS in a Popular React Component Library
Introduction
Last month, while auditing a widely-used React component library for a client project, I stumbled upon a stored Cross-Site Scripting (XSS) vulnerability that had been hiding in plain sight for over two years.
The Vulnerability
The library provided a MarkdownRenderer component that allowed users to render markdown content. The issue was in how it handled HTML sanitization…
// Vulnerable code
function MarkdownRenderer({ content }) {
const html = markdownToHtml(content);
return <div dangerouslySetInnerHTML={{ __html: html }} />;
}
The library used a popular sanitization library but had misconfigured it to allow data- attributes, which led to the bypass.
The Exploit
An attacker could craft markdown like:
 data-x=")
This would execute JavaScript in the context of any application using the component.
Responsible Disclosure
- Day 1: Reported to maintainers via GitHub Security Advisory
- Day 3: Maintainers acknowledged and began working on a fix
- Day 7: Patch released in v3.2.1
- Day 14: Public disclosure after users had time to update
Lessons Learned
- Never trust
dangerouslySetInnerHTML– Even with sanitization - Audit your dependencies – Regular security reviews are essential
- Use Content Security Policy – Defense in depth matters
- Test with real attack vectors – Automated tools miss context-specific issues
Conclusion
This vulnerability affected over 500,000 weekly downloads. The fix was straightforward, but the impact could have been massive. Always sanitize, always validate, and never assume a popular library is immune to security issues.
