React application uses unsanitized user input in component properties or attributes, potentially leading to cross-site scripting (XSS) attacks through property injection.
import React from 'react';
import { useState } from 'react';
interface UserProfileProps {
userInput: string;
className?: string;
style?: React.CSSProperties;
}
// Vulnerable: Direct user input in properties
const UserProfile: React.FC = ({ userInput, className, style }) => {
return (
{userInput}
{/* Vulnerable: Unsanitized content */}
);
};
// Vulnerable: Dynamic property assignment
const DynamicComponent: React.FC = () => {
const [userProps, setUserProps] = useState({});
const handleUserInput = (input: string) => {
// Dangerous: Direct assignment of user data
const props = JSON.parse(input); // Can contain malicious properties
setUserProps(props);
};
return (
{/* Extremely dangerous: Spread operator with user data */}
Content
React component sets DOM properties with user input: element.innerHTML = userInput or element.outerHTML = data. Direct DOM manipulation bypasses React's XSS protection. innerHTML interprets HTML. User input with <script> tags executes. Unsanitized assignment enables XSS.
Root causes
Using Unsanitized User Input in DOM Property Assignments
React component sets DOM properties with user input: element.innerHTML = userInput or element.outerHTML = data. Direct DOM manipulation bypasses React's XSS protection. innerHTML interprets HTML. User input with <script> tags executes. Unsanitized assignment enables XSS.
Setting href or src Attributes Without Validation
Dynamic attributes with user data: <a href={userInput}>Link</a> or <img src={params.imageUrl} />. userInput may contain javascript: protocol. javascript:alert(1) executes code. data: URLs with HTML. User-controlled URLs in href/src create XSS vectors.
Using dangerouslySetInnerHTML with User Content
React dangerouslySetInnerHTML: <div dangerouslySetInnerHTML={{__html: userContent}} />. Bypasses React escaping. HTML from user input rendered directly. Script tags and event handlers execute. API responses or database content containing HTML. dangerouslySetInnerHTML requires sanitization.
Setting Event Handlers from String Attributes
Dynamic event handlers: element.setAttribute('onclick', userCode). String-based event handler from user input. onclick evaluates JavaScript. User controls code execution. Any on* attribute with user data vulnerable. Attribute-based handlers bypass CSP protections.
Using eval or Function Constructor with User Data
Code evaluation in React: eval(userInput) or new Function(userCode)(). Arbitrary JavaScript execution. User input as code. eval and Function constructor execute strings. React components calling eval with props or state from untrusted sources.
Fixes
1
Use React's JSX Auto-Escaping, Never Direct DOM Manipulation
Rely on JSX escaping: <div>{userInput}</div>. React automatically escapes. HTML special characters rendered as text. No innerHTML or outerHTML. Use React state and props. Virtual DOM handles updates safely. Auto-escaping prevents XSS.
2
Validate and Sanitize URLs Before Using in href/src
Use DOMPurify to Sanitize HTML Before dangerouslySetInnerHTML
Sanitize with DOMPurify: import DOMPurify from 'dompurify'; const clean = DOMPurify.sanitize(dirtyHTML); <div dangerouslySetInnerHTML={{__html: clean}} />. Removes scripts, event handlers, dangerous attributes. Configure allowed tags. Industry-standard HTML sanitizer. Required for any user-generated HTML.
4
Never Use String-Based Event Handlers, Use JSX Event Props
React event handling: <button onClick={handleClick}>. Function references, not strings. Type-safe handlers. No setAttribute with on* attributes. React synthetic events. JSX syntax prevents code injection through event handlers.
5
Never Use eval or Function Constructor
Avoid eval entirely: no eval(userInput) or new Function(userCode). No safe way to use with untrusted data. Replace with JSON.parse for data. Use parsers for expressions. Sandboxed environments if dynamic code required. eval with user input is code execution.
6
Implement Content Security Policy for Defense-in-Depth
CSP headers: Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}'. Blocks inline scripts. Requires nonces for legitimate inline scripts. External scripts from trusted domains only. CSP prevents XSS execution even if escaping bypassed.