highCWE-79A03:2021

dangerouslySetInnerHTML Without Sanitization

Using React's dangerouslySetInnerHTML with unsanitized user input allows attackers to inject malicious scripts that execute in other users' browsers.

How It Works

React escapes content by default, preventing XSS. However, dangerouslySetInnerHTML bypasses this protection and renders raw HTML. When the HTML comes from user input (comments, profile bios, rich text editors), attackers inject script tags, event handlers (onerror, onload), or JavaScript URIs that execute in other users' browsers. This enables session hijacking, credential theft, and account takeover. The attack persists because the malicious HTML is stored in the database and rendered for every visitor.

Vulnerable Code
function Comment({ comment }) {
  return (
    <div
      dangerouslySetInnerHTML={{ __html: comment.body }}
    />
  );
}
Secure Code
import DOMPurify from 'dompurify';

function Comment({ comment }) {
  const sanitized = DOMPurify.sanitize(comment.body, {
    ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br'],
    ALLOWED_ATTR: ['href']
  });
  return (
    <div dangerouslySetInnerHTML={{ __html: sanitized }} />
  );
}

Real-World Example

In 2020, a Stored XSS vulnerability in Webflow's CMS allowed attackers to inject JavaScript through rich text fields. The malicious code executed for every visitor viewing the affected page, potentially compromising thousands of users.

How to Prevent It

  • Always sanitize HTML with DOMPurify before using dangerouslySetInnerHTML
  • Restrict allowed tags and attributes to the minimum necessary
  • Prefer rendering Markdown with a safe parser instead of raw HTML
  • Use Content Security Policy headers to mitigate XSS impact

Affected Technologies

ReactNext.jsNode.js

Data Hogo detects this vulnerability automatically.

Scan Your Repo Free

Related Vulnerabilities