What Is XSS (Cross-Site Scripting)?
Cross-Site Scripting (XSS) lets attackers inject malicious scripts into web pages viewed by other users. It can steal session cookies, redirect users, and deface websites — and it is one of the most common web vulnerabilities.
Cross-Site Scripting (XSS) is a web [vulnerability](/learning-center/what-is-sql-injection-and-xss-web-application-attacks-explained) where an attacker injects malicious JavaScript (or other client-side code) into a web page that is then executed in the browser of another user. Unlike server-side attacks, XSS runs in the victim's browser — with the victim's privileges.
XSS consistently appears in the [OWASP Top 10](/learning-center/gdpr-HIPAA-PCI-DSS-cybersecurity-compliance-frameworks-explained) and is one of the most reported vulnerabilities in bug bounty programmes.
What Can an Attacker Do with XSS?
- Steal session-how-the-world-wide-web-works) cookies — hijacking authenticated sessions to impersonate the victim
- Capture keystrokes — logging passwords and form inputs
- Redirect to phishing pages — sending victims to malicious lookalike sites
- Deface web pages — replacing page content with attacker-controlled material
- Install browser-based malware — exploiting browser vulnerabilities
- Perform actions on behalf of the victim — submitting forms, changing account details, transferring funds
The Three Types of XSS
1. Reflected XSS (Non-Persistent)
The malicious script is embedded in a URL parameter and reflected back by the server in its response. The victim must click a crafted link for the attack to execute.
Example: A search page echoes the query back to the user:
https://example.com/search?q=When the victim clicks this link, the server echoes the script into the page, and the browser executes it — sending the victim's cookies to the attacker.
How it spreads: Via email, social media, or any other link-sharing mechanism. The attacker must trick users into clicking the crafted URL.
2. Stored XSS (Persistent)
The malicious script is stored in the application's database (e.g. in a comment, profile field, or message) and served to every user who views that content. No crafted link needed — every visitor is a victim.
Example: An attacker posts a comment on a forum:
Great article! If the site renders this HTML without sanitisation, every user who reads that comment executes the script.
Stored XSS is generally more dangerous than reflected XSS because it does not require tricking individual users into clicking links.
3. DOM-Based XSS
The vulnerability exists entirely in client-side JavaScript, not in server-rendered HTML. The attack occurs when JavaScript reads attacker-controlled data (from the URL fragment, document.referrer, or localStorage) and writes it unsafely to the DOM.
Example:
// Vulnerable code
document.getElementById('welcome').innerHTML = location.hash.substring(1);
// Attack URL: https://example.com/page#<img src=x onerror=alert(document.cookie)>DOM XSS is harder to detect because the malicious payload never reaches the server — it lives entirely in the browser.
A Typical XSS Attack Flow
1. Attacker discovers a page that reflects/stores user input
2. Attacker injects a script payload into the input
3. Victim loads the page — browser executes the script
4. Script exfiltrates cookies/credentials to attacker's server
5. Attacker uses stolen session cookie to impersonate victimHow to Prevent XSS
1. Output Encoding (HTML Escaping)
The primary defence. Before inserting any user-supplied data into HTML, encode special characters so the browser treats them as data, not code:
| Character | Encoded form | |---|---| | < | < | | > | > | | " | " | | ' | ' | | & | & |
Modern templating engines (Jinja2, Handlebars, React JSX) do this automatically for variables. Never use innerHTML, document.write(), or eval() with user input.
2. Content Security Policy (CSP)
A HTTP response header that tells the browser which sources of scripts to trust:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.comEven if an attacker injects a script, the browser will refuse to execute it if it violates the policy. CSP is a powerful second layer of defence but requires careful configuration.
3. Input Sanitisation
Validate and strip dangerous content from user inputs before storing or processing them. Use dedicated libraries:
- DOMPurify (JavaScript) — sanitises HTML
- Bleach (Python) — allow-lists safe HTML tags
- OWASP Java HTML Sanitizer
Never write your own sanitiser — edge cases in HTML parsing make it extremely difficult to get right.
4. Use HTTPOnly and Secure Cookie Flags
Setting HttpOnly on session-how-the-world-wide-web-works) cookies prevents JavaScript from reading them — breaking the most common XSS attack goal (cookie theft). This does not prevent XSS itself but limits its impact.
5. Avoid Dangerous JavaScript APIs
audit your code for sink functions that write to the DOM without encoding:
innerHTML→ usetextContentinsteaddocument.write()eval(),setTimeout(string),setInterval(string)- jQuery's
html(),append()with user data
Testing for XSS
The classic test payload is:
If the alert fires, the page is vulnerable. Automated tools:
| Tool | Type | |---|---| | Burp Suite Pro | Active scanner with XSS detection | | OWASP ZAP | Free scanner | | XSStrike | Advanced XSS detection and fuzzing | | Dalfox | Fast DOM/reflected XSS scanner |
XSS vs CSRF
| | XSS | CSRF | |---|---|---| | What it does | Runs code in victim's browser | Tricks victim's browser into making a request | | Goal | Steal data, hijack session-how-the-world-wide-web-works) | Perform an action on an authenticated site | | Requires | Application reflects/stores the payload | Victim is authenticated on the target site | | Defence | Output encoding, CSP | CSRF tokens, SameSite cookies |
Key Takeaways
- XSS injects scripts into web pages that execute in other users' browsers
- Three types: reflected (link-based), stored (database), DOM-based (client-side JS)
- Primary defence: output encode all user-supplied data before rendering in HTML
- Content Security Policy-security-headers-CORS-HSTS-explained)-csp-hsts-explained) (CSP) limits damage even if XSS occurs
- Use HTTPOnly cookies, avoid unsafe DOM APIs, and sanitise HTML input