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.
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
- Explain the three types of XSS attacks.
- Attempt to attack our custom-built web application.
- Detect vulnerabilities using the XSStrike tool.
- 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/ ├── 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 IMPACTDOM-Based XSS
The attack occurs entirely in the browser by manipulating the DOM. The server is never involved in the exploit.
CLIENT-SIDEReflected XSS
Malicious input is immediately reflected back in the server's response and executed in the victim's browser.
ONE-TIMEStored 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)
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
# 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)
<script> let input = location.hash.substring(1); // ❌ innerHTML parses and executes injected HTML/JS document.getElementById("output").innerHTML = decodeURIComponent(input); </script>
// Attack Payload
# 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)
<?php $q = $_GET['q'] ?? ''; ?> <!-- ❌ $q echoed directly — no encoding --> <p>Results for: <?php echo $q; ?></p>
// Attack Payload
# 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:
- Visits a target web page.
- Identifies all links, forms, and input fields on that page.
- Follows those links to discover additional pages.
- Repeats this process recursively across the entire site.
Installation
$ cd XSStrike
$ pip install -r requirements.txt --break-system-packages
# XSStrike is now ready to use
How Payload Generation Works
- Injects a test input into the target field.
- Observes how the website reflects or processes the input.
- Analyzes the context (HTML tag, attribute, JavaScript, etc.).
- 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
[+] 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
[!] 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
[~] 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.
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
[+] 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:
htmlspecialchars()
Converts dangerous characters (<, >, ", ') into safe HTML-encoded equivalents so they render as text, not code.
textContent vs innerHTML
Replaced innerHTML with textContent. Unlike innerHTML, textContent does not parse HTML, so injected tags are treated as literal text.
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
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
<?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
<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
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 |