Finding a Stored XSS in a Popular React Component Library

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:

![image](x onerror=alert(1) data-x=")

This would execute JavaScript in the context of any application using the component.

Responsible Disclosure

  1. Day 1: Reported to maintainers via GitHub Security Advisory
  2. Day 3: Maintainers acknowledged and began working on a fix
  3. Day 7: Patch released in v3.2.1
  4. Day 14: Public disclosure after users had time to update

Lessons Learned

  1. Never trust dangerouslySetInnerHTML – Even with sanitization
  2. Audit your dependencies – Regular security reviews are essential
  3. Use Content Security Policy – Defense in depth matters
  4. 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.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *