Security Lab Report

XSStrike Vulnerability Report XSS Detection & Analysis

A hands-on investigation into Cross-Site Scripting attacks — how they work,
how they're detected with automated tools, and how to defend against them.

Stored XSS DOM-Based XSS Reflected XSS XSStrike Tool
scroll to explore

XSS Attack Overview

XSS stands for Cross-Site Scripting. It is a web security vulnerability in which an attacker injects malicious JavaScript code into a trusted website. This code is then executed in the browser of any unsuspecting user who visits the affected page.

XSS vulnerabilities are among the most prevalent web security risks and can lead to session hijacking, credential theft, defacement, and malware distribution.

Objectives

  1. Explain the three types of XSS attacks.
  2. Attempt to attack our custom-built web application.
  3. Detect vulnerabilities using the XSStrike tool.
  4. Apply security fixes to protect the website against XSS attacks.

Lab Code Structure

The lab web application was built with PHP and MySQL and structured as follows:

xss-lab/ — project tree
xss-lab/
├── config.php        # Database connection
├── index.php         # Main page (entry point)
├── login.php         # Simple login (sets cookie)
├── dashboard.php     # Displays session cookie
├── search.php        # Reflected XSS lab
├── comments.php      # Stored XSS lab
├── dom.php           # DOM XSS lab
├── style.css         # UI styling
└── (database)
     ├── users
     └── comments

Types of XSS Attacks

There are three main categories of XSS attacks, each with a different mechanism and impact.

🗄️

Stored XSS

The malicious script is saved in the server's database and executed every time a user loads the affected page.

HIGH IMPACT

DOM-Based XSS

The attack occurs entirely in the browser by manipulating the DOM. The server is never involved in the exploit.

CLIENT-SIDE
🔄

Reflected XSS

Malicious input is immediately reflected back in the server's response and executed in the victim's browser.

ONE-TIME

Stored XSS

In a Stored XSS attack, the attacker submits a malicious script through the browser, which is then saved in the application's database. Every time a user retrieves that data, the malicious script is executed in their browser. This type of attack is particularly dangerous because it can affect a large number of users without requiring any direct interaction from the attacker.

// Vulnerable Code — comments.php (before fix)

comments.php — vulnerable version
if ($_POST) {
    $comment = $_POST['comment'];

    // ❌ No sanitization — input stored directly
    $stmt = $conn->prepare("INSERT INTO comments(content) VALUES(?)");
    $stmt->bind_param("s", $comment);
    $stmt->execute();
}

$result = $conn->query("SELECT * FROM comments");
while ($row = $result->fetch_assoc()) {
    // ❌ Directly echoed — XSS executes here
    echo "<p>" . $row['content'] . "</p>";
}

// Attack Payload

payload $ <script> alert("stored xss") </script>
# Submitted as a comment → stored in DB → executed for every visitor

The attack succeeded because user input was stored in the database without any validation or sanitization. Every subsequent visitor to the comments page triggered the alert.

DOM-Based XSS

JavaScript has the ability to read and manipulate the DOM (Document Object Model). Attackers exploit this capability by injecting HTML tags into the page URL. The browser then renders the injected content directly without any server involvement.

// Vulnerable Code — dom.php (before fix)

dom.php — vulnerable version
<script>
    let input = location.hash.substring(1);

    // ❌ innerHTML parses and executes injected HTML/JS
    document.getElementById("output").innerHTML = decodeURIComponent(input);
</script>

// Attack Payload

url $ http://localhost/mywebsite/dom.php#<h1 style=color:red>Site is down now, try later</h1>
# Hash fragment read by JS → injected into innerHTML → rendered as HTML

This attack affects only the user who clicks the crafted link. No server-side processing is involved and the payload is never stored. The attack succeeded because user input was passed directly into innerHTML without sanitization.

Reflected XSS

In a Reflected XSS attack, the victim sends malicious input to a server, which immediately reflects it back in the HTTP response. The browser then executes the reflected script. Unlike Stored XSS, the payload is not saved on the server.

// Vulnerable Code — search.php (before fix)

search.php — vulnerable version
<?php
$q = $_GET['q'] ?? '';
?>

<!-- ❌ $q echoed directly — no encoding -->
<p>Results for: <?php echo $q; ?></p>

// Attack Payload

url $ search.php?q=<img src=x onerror="alert('XSS')">
# GET param reflected into HTML → onerror fires → JS executes

The attack succeeded because the application uses the GET method and does not validate or encode user input before reflecting it in the response. This attack affects only one user per request, and while the server is involved, the query is not stored anywhere.

XSStrike Tool

🛠️

What is XSStrike?

XSStrike is an advanced XSS detection tool that automates the process of identifying cross-site scripting vulnerabilities. Unlike basic scanners, it generates intelligent, context-aware payloads by first analyzing how the target reflects input, then crafting payloads suited to that specific context.

The tool works through a process called crawling:

  1. Visits a target web page.
  2. Identifies all links, forms, and input fields on that page.
  3. Follows those links to discover additional pages.
  4. Repeats this process recursively across the entire site.

Installation

$ git clone https://github.com/s0md3v/XSStrike
$ cd XSStrike
$ pip install -r requirements.txt --break-system-packages
# XSStrike is now ready to use

How Payload Generation Works

  1. Injects a test input into the target field.
  2. Observes how the website reflects or processes the input.
  3. Analyzes the context (HTML tag, attribute, JavaScript, etc.).
  4. Constructs a custom payload suited to that specific context.

What to Expect During a Scan

  • Reflected parameters detected in the response.
  • Payloads generated and used during testing.
  • Execution confirmation for each payload.
  • Vulnerable context identified (HTML or JavaScript).

Running XSStrike Against the Lab

4.1 Crawling the Website

$ python3 xsstrike.py -u "http://localhost/mywebsite/index.php" --crawl
[+] Crawling URL: http://localhost/mywebsite/index.php
[+] Found 5 pages (5/5) — crawl complete

// Discussion

XSStrike successfully scanned and explored the entire website structure, discovering all five pages (5/5). At this stage, no vulnerabilities are reported because the tool is only identifying pages and has not yet begun testing them for XSS.

4.2 Stored XSS Detection Attempt

$ python3 xsstrike.py -u "http://localhost/mywebsite/comments.php" --data "comment=test"
[!] No vulnerabilities detected

// Discussion

XSStrike did not detect the Stored XSS vulnerability. This is expected behavior: Stored XSS via POST forms requires a multi-step interaction — the payload must be submitted, stored, and then retrieved on a subsequent request — a workflow that XSStrike does not fully automate. Manual testing confirmed the vulnerability exists.

4.3 DOM-Based XSS Detection Attempt

$ python3 xsstrike.py -u "http://localhost/mywebsite/dom.php"
[~] Risky JavaScript pattern detected:
innerHTML = decodeURIComponent(input)
[!] Input is behind # fragment — cannot confirm exploitability

// Discussion

XSStrike identified risky JavaScript patterns but could not fully test them. The vulnerable input is read from the URL fragment (after the # symbol), which is processed entirely on the client side and never transmitted to the server, making it inaccessible to the tool's analysis.

dom.php — risky pattern
let input = location.hash.substring(1);
// ↑ reads from URL fragment — invisible to server

document.getElementById("output").innerHTML = decodeURIComponent(input);
// ↑ innerHTML executes any injected HTML or JS

4.4 Reflected XSS Detection Attempt

$ python3 xsstrike.py -u "http://localhost/mywebsite/search.php?q=test"
[+] Testing parameter: q
[+] Reflections found: 1
[+] Analysing reflection context...
[+] Generating payloads: 3072 payloads generated
[✓] Payload executed successfully
[✓] Confidence: 10 — VULNERABILITY CONFIRMED

// Discussion

XSStrike successfully detected the Reflected XSS vulnerability with the following findings:

  • Detected vulnerable parameter: q
  • Confirmed 100% injectable — Reflections found: 1
  • Generated 3,072 context-aware payloads, all successfully executed
  • Vulnerability confirmed with maximum confidence — Confidence: 10

Securing the Website

After confirming the vulnerabilities, the following security fixes were applied:

Fix 01 — Stored & Reflected XSS

htmlspecialchars()

Converts dangerous characters (<, >, ", ') into safe HTML-encoded equivalents so they render as text, not code.

Fix 02 — DOM-Based XSS

textContent vs innerHTML

Replaced innerHTML with textContent. Unlike innerHTML, textContent does not parse HTML, so injected tags are treated as literal text.

Fix 03 — Cookie Security

HttpOnly & SameSite

Added HttpOnly and SameSite=Strict attributes to all cookies, preventing JavaScript from accessing session tokens and reducing CSRF risk.

Fixed Code Examples

// comments.php — after fix

comments.php — secure version
while ($row = $result->fetch_assoc()) {
    // ✅ htmlspecialchars encodes output — safe to render
    echo "<p>" . htmlspecialchars($row['content'], ENT_QUOTES, 'UTF-8') . "</p>";
}

// search.php — after fix

search.php — secure version
<?php
$q      = $_GET['q'] ?? '';
$safe_q = htmlspecialchars($q, ENT_QUOTES, 'UTF-8');
?>

<!-- ✅ $safe_q is encoded — no XSS possible -->
<p>Results for: <?php echo $safe_q; ?></p>

// dom.php — after fix

dom.php — secure version
<script>
    let input = location.hash.substring(1);

    // ✅ textContent — no HTML parsing, no script execution
    document.getElementById("output").textContent = decodeURIComponent(input);
</script>

// login.php — secure cookie

login.php — secure version
setcookie("session", "admin_session", [
    'expires'  => time() + 3600,
    'httponly' => true,    // ✅ JS cannot read this cookie
    'samesite' => 'Strict'  // ✅ blocks cross-site requests
]);

Re-Attack Results After Patching

Attack Type Method Used Result Notes
DOM-Based XSS Manual ✗ Blocked textContent prevents HTML execution
Reflected XSS XSStrike + Manual ✗ Blocked htmlspecialchars encodes all payloads
Stored XSS Manual ✗ Blocked Output encoded before rendering

Notably, XSStrike reported a false positive for Reflected XSS after patching — it detected that user input is reflected in the page, but could not verify whether the JavaScript actually executes. Manual testing confirmed no execution occurred. This demonstrates why automated tools must always be combined with manual verification.

Summary & Findings

In this experiment, XSStrike was used to test the web application against three types of XSS attacks. Here is a consolidated view of the results:

Attack XSStrike Manual After Fix
Reflected XSS ✓ Detected ✓ Confirmed ✗ Blocked
Stored XSS ✗ Missed ✓ Confirmed ✗ Blocked
DOM-Based XSS △ Partial ✓ Confirmed ✗ Blocked

Key Takeaways

🎯
XSStrike excels at Reflected XSS It identified the vulnerable parameter, confirmed reflectability, and generated 3,072 payloads — all successfully executed with Confidence: 10.
⚠️
Stored XSS requires manual testing XSStrike cannot automate multi-step POST flows. The payload must be stored then retrieved — a workflow beyond the tool's current scope.
🔍
DOM-Based XSS is partially detectable XSStrike flags risky patterns but cannot confirm exploitability when input comes from the URL fragment, which is invisible to the server.
🤖
Automated tools have limits XSStrike produced a false positive on the patched Reflected XSS endpoint. Always combine automated scanning with manual verification for accurate assessments.
🛡️
Defense is straightforward htmlspecialchars() for server-side output, textContent for DOM manipulation, and HttpOnly + SameSite cookies eliminate all three attack vectors.