flawopen.com/XSS in JavaScript/dangerouslySetInnerHTML

Is React's dangerouslySetInnerHTML safe?

Reference page — draft, pending review
Short answer

Only if the HTML string you pass it never contains untrusted content unsanitized. The name is a deliberate warning, not a formality — React is telling you it's stepping outside its own safety guarantees.

Why normal JSX doesn't need this

RISKY — the escape hatch
function Comment(props) {
  return <p dangerouslySetInnerHTML=
    {{ __html: props.html }} />;
}
// html is parsed as real markup —
// a <script> tag would run
SAFE — normal JSX interpolation
function Comment(props) {
  return <p>{props.text}</p>;
}
// text is escaped automatically,
// even if it contains "<script>"

When it's actually needed

Legitimate cases exist — rendering HTML from a trusted CMS/rich-text editor, or a markdown renderer's output. The safety question isn't whether to ever use it, it's whether the string reaching it has been sanitized against a strict allow-list of tags and attributes immediately before use.

Doing it correctly

Sanitize immediately before rendering, not at input time

Sanitizing when data is saved and trusting it forever afterward misses cases where the sanitizer itself gets updated or bypassed later — sanitize at the point of render, using a maintained library like DOMPurify, not custom regex-based stripping.

A strict allow-list, not a block-list

Blocking known-bad tags (<script>) misses event-handler attributes (onerror, onload) and other vectors. An allow-list of specifically permitted tags/attributes is the only approach that doesn't require anticipating every attack variant.

How to check your codebase

grep -rn "dangerouslySetInnerHTML" --include="*.jsx" --include="*.tsx" .
For each hit, trace back to where the HTML string originates — if it's ever influenced by user input or third-party data without passing through a sanitizer immediately before this line, it's a real risk, not a false positive.

FAQ

Is markdown rendering automatically safe?

Not automatically — most markdown renderers pass raw HTML embedded in the markdown source straight through unless explicitly configured to sanitize or disable raw HTML.

Does this apply to Vue's v-html the same way?

Yes — same mechanism, same rule: sanitize untrusted content immediately before it reaches v-html, never trust it by default.

References