1. Vulnerable sink
Assigning untrusted input to innerHTML parses it as HTML, so a <script> or onerror payload runs in the user's page.
el.innerHTML = userInput;Typorithm · medium
Step 1 of 8 · intro card
Web Security (OWASP)
XSS injects attacker-controlled script into a page (reflected, stored, or DOM-based). The defenses are output encoding/escaping, preferring textContent over innerHTML, a Content-Security-Policy, and a sanitizer like DOMPurify when you must render rich HTML.
Cross-Site Scripting runs an attacker's JavaScript in another user's browser. It comes in three flavors: reflected (payload bounced back from a request), stored (payload saved and served to others), and DOM-based (client-side code writes input into the page). All of them stem from putting untrusted input where the browser will treat it as code.
The core fix is output encoding: render data as text, not markup. Assigning to textContent escapes the value, while innerHTML parses it as HTML and is the most common XSS sink. Modern frameworks like React escape interpolated values automatically, so {userInput} is safe.
Add defense in depth with a Content-Security-Policy that blocks inline and untrusted scripts, so even an injected payload struggles to execute. When you genuinely need to render user-supplied HTML, run it through a vetted sanitizer such as DOMPurify rather than trusting it.
XSS runs attacker script in a victim's browser.
Encode output: textContent over innerHTML.
CSP and DOMPurify add defense in depth.
// VULNERABLE: raw HTML injection
el.innerHTML = userInput;
// SAFE: textContent escapes
el.textContent = userInput;
// frameworks escape by default
return <div>{userInput}</div>;Connect each part of the code to the concept before you type.
Assigning untrusted input to innerHTML parses it as HTML, so a <script> or onerror payload runs in the user's page.
el.innerHTML = userInput;textContent sets the text of the node, so any HTML in the input is shown literally and never executed.
el.textContent = userInput;JSX (and similar templates) escape interpolated values by default, so {userInput} is rendered as text.
return <div>{userInput}</div>;The framework HTML-encodes the value at this binding point, so tags in userInput become harmless text.
{userInput}Read the concept map and follow the code breakdown.
Type the implementation, repair mistakes and work through every recall exercise.
Use the final check without hints; revisit weak concepts in short practice sessions.