Help us improve
Share bugs, ideas, or general feedback.
From prodsec-skills
Enforce XSS prevention in React apps: safe JSX binding, sanitizing dangerouslySetInnerHTML with DOMPurify, validating URLs, avoiding SSR concatenation, and escaping preloaded state.
npx claudepluginhub redhatproductsecurity/prodsec-skills --plugin prodsec-skillsHow this skill is triggered — by the user, by Claude, or both
Slash command
/prodsec-skills:react-securityThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
React escapes values rendered via JSX data binding by default, but several patterns can reintroduce XSS vulnerabilities. This skill covers the most common pitfalls.
Block script injection by encoding output, sanitizing HTML, and enforcing Content Security Policy.
Eliminates XSS by context-aware output encoding and content security policies. Trigger when rendering user content in HTML/DOM or building browser-rendered APIs.
Prevents XSS attacks via input sanitization, output encoding, CSP headers, DOMPurify, and safe DOM APIs. Use for user-generated content, rich text editors, comments, and dynamic HTML.
Share bugs, ideas, or general feedback.
React escapes values rendered via JSX data binding by default, but several patterns can reintroduce XSS vulnerabilities. This skill covers the most common pitfalls.
React automatically escapes values inside curly braces when rendering text content. This protection does not apply to HTML attributes.
Safe -- text content is escaped:
<div>{userData}</div>
Unsafe -- attribute values are not automatically escaped:
<form action={userData}>...</form>
Always validate or sanitize values placed in HTML attributes, especially href, src, action, and event handler attributes.
Never pass unsanitized data to dangerouslySetInnerHTML. Always sanitize with a library like DOMPurify before rendering raw HTML.
Safe:
import DOMPurify from "dompurify";
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(data) }} />
Unsafe:
this.myRef.current.innerHTML = attackerControlledValue;
Direct DOM manipulation via refs bypasses React's escaping entirely.
URLs can contain executable content via javascript: protocol URIs. Validate that URLs use http: or https: before rendering them.
Safe:
function validateURL(url) {
const parsed = new URL(url);
return ["https:", "http:"].includes(parsed.protocol);
}
<a href={validateURL(url) ? url : ""}>Click here</a>
Unsafe:
<a href={attackerControlled}>Click here</a>
ReactDOMServer.renderToString() and ReactDOMServer.renderToStaticMarkup() provide automatic content escaping for data bound through JSX. Do not concatenate unsanitized data with their output.
Unsafe SSR pattern:
const html = ReactDOMServer.renderToString(<App />) + unsanitizedData;
When embedding serialized state in SSR HTML, escape HTML-significant characters to prevent script injection via closing </script> tags.
Safe:
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, "\\u003c")}
{} binding, not string concatenationdangerouslySetInnerHTML is only used with DOMPurify-sanitized contentref.current.innerHTMLhref and src values are validated for http:/https: protocol< as \u003ceval(), Function(), or inline event handlers