## https://sploitus.com/exploit?id=CC02DC93-529C-56EA-80F3-1CE20F705330
# Stored Cross-Site Scripting (XSS) Vulnerability Report
## Executive Summary
This report documents the implementation, exploitation, and mitigation of a **Stored Cross-Site Scripting (XSS)** vulnerability in a vulnerable blog application. The project demonstrates how user input stored in a database (localStorage) can execute malicious JavaScript code when displayed to other users, and implements a defense-in-depth mitigation strategy using both input sanitization and safe output rendering.
---
## 1. Chosen Vulnerability: Stored Cross-Site Scripting (XSS)
### 1.1 Vulnerability Type
**Stored XSS (Persistent XSS)** - Type 2 XSS vulnerability
### 1.2 Description
Stored XSS occurs when malicious scripts are permanently stored on a target server (or client-side storage) and executed when other users view the stored content. Unlike Reflected XSS, the payload persists across sessions and affects all users who view the compromised content.
### 1.3 Risk Level
**HIGH** - Stored XSS is considered more dangerous than Reflected XSS because:
- The attack persists indefinitely
- All users viewing the content are affected
- Can lead to session hijacking, cookie theft, defacement, and malware distribution
- No user interaction required beyond viewing the page
### 1.4 Impact
- **Session Hijacking**: Steal user session cookies
- **Account Takeover**: Perform actions on behalf of users
- **Data Theft**: Extract sensitive information from the page
- **Malware Distribution**: Redirect users to malicious sites
- **Website Defacement**: Modify page content
- **Phishing Attacks**: Create fake login forms
---
## 2. Implementation
### 2.1 Project Structure
```
cyber_sec_project/
โโโ index.html # Main HTML structure
โโโ script.js # JavaScript logic (vulnerability & mitigation)
โโโ styles.css # Styling
```
### 2.2 Technologies Used
- **HTML5**: Page structure and form elements
- **JavaScript (ES6+)**: Client-side logic and DOM manipulation
- **localStorage API**: Client-side data persistence (simulating database)
- **DOMPurify Library v3.0.8**: HTML sanitization library (CDN)
- **CSS3**: Styling and responsive design
### 2.3 Vulnerable Code Implementation
#### 2.3.1 Data Storage Mechanism
The application uses `localStorage` to simulate a database, storing blog posts and comments persistently:
```javascript
// Save posts data to localStorage
function savePostsData() {
localStorage.setItem("postsData", JSON.stringify(postsData));
}
// Load posts data from localStorage or use default
function loadPostsData() {
const saved = localStorage.getItem("postsData");
if (saved) {
return JSON.parse(saved);
}
// ... default data
}
```
#### 2.3.2 Vulnerable Comment Submission
The `addComment()` function accepts user input without sanitization:
```javascript
function addComment(event) {
event.preventDefault();
const postId = document.getElementById("current-post-id").value;
let author = document.getElementById("comment-author").value;
let commentText = document.getElementById("comment-text").value;
// VULNERABILITY: No input sanitization
// The comment text is stored and displayed as it is once loaded
const comment = {
id: Date.now(),
author: author, // Unsanitized user input
text: commentText, // Unsanitized user input
date: new Date().toLocaleString(),
};
// Store the comment (persists in localStorage)
postsData[postId].comments.push(comment);
savePostsData();
// Display comments (vulnerable rendering)
displayComments(postId);
}
```
**Vulnerability Point**: User input (`author` and `commentText`) is stored directly without validation or sanitization.
#### 2.3.3 Vulnerable Display Function
The `displayComments()` function uses `innerHTML` with unsanitized user content:
```javascript
function displayComments(postId) {
const commentsContainer = document.getElementById("comments-list");
const comments = postsData[postId].comments;
let commentsHTML = "";
comments.forEach((comment) => {
// VULNERABILITY: innerHTML with unsanitized user content
commentsHTML += `
${comment.author}
${comment.text}
${comment.date}
`;
});
// VULNERABLE: Setting innerHTML with user-controlled content
commentsContainer.innerHTML = commentsHTML;
}
```
**Vulnerability Point**: Template literals with `innerHTML` allow JavaScript execution. Any HTML/JavaScript in `comment.author` or `comment.text` will be executed.
### 2.4 Why This Implementation is Vulnerable
1. **No Input Validation**: User input is accepted as-is without checking for malicious patterns
2. **Unsafe DOM Manipulation**: Using `innerHTML` with user-controlled data allows script execution
3. **Persistent Storage**: Malicious payloads are stored and persist across sessions
4. **No Output Encoding**: Data is displayed without HTML entity encoding
### 2.5 Important Note: Browser Security and `` Tags
**Modern browsers have built-in XSS protection** that prevents `` tags from executing when inserted via `innerHTML`. This is why `alert('XSS')` may appear to be "sanitized" even in vulnerable mode.
**However, the application is still vulnerable** to other XSS vectors:
- โ **Event Handlers**: `` - **WORKS**
- โ **SVG with handlers**: `` - **WORKS**
- โ **iframe with javascript**: `` - **WORKS**
- โ **Script tags**: `alert('XSS')` - **DOESN'T WORK** (browser protection)
This is why the demo payload uses `` instead of `` tags. The vulnerability is real and dangerous - attackers simply need to use event handlers or other HTML elements instead of script tags.
---
## 3. Exploitation
### 3.1 Attack Vector
The vulnerability can be exploited through the comment submission form, where attackers inject malicious JavaScript code.
### 3.2 Exploitation Steps
#### Step 1: Access the Vulnerable Application
1. Open `index.html` in a web browser
2. Navigate to any blog post (e.g., "Ocean Sunset")
3. Scroll to the comments section
#### Step 2: Inject Malicious Payload
In the comment form, enter a malicious payload:
**Example Payload 1: Alert Popup (Event Handler) - โ WORKS**
```
```
**Example Payload 2: SVG with onload - โ WORKS**
```
```
**Note**: `` tags do NOT work with `innerHTML` due to browser security, but event handlers on HTML elements DO work and are equally dangerous.
#### Step 3: Submit the Comment
1. Enter a name (e.g., "Attacker")
2. Paste the malicious payload in the comment field
3. Click "Post Comment"
#### Step 4: Payload Execution
- The malicious code is stored in `localStorage`
- When the page displays comments, the payload executes automatically
- All users viewing this post will have the script executed in their browser context
### 3.3 Proof of Concept
The application includes a demo payload pre-loaded in Post 2 ("Ocean Sunset"):
```javascript
// Demo malicious comment injected on page load
postsData[2].comments.push({
id: 2,
author: "Bassant the attacker",
text: 'This comment contains a hidden XSS payload that executes when viewed!',
date: new Date(Date.now() - 3600000).toLocaleString(),
});
```
**To see the vulnerability:**
1. Open the application with `SANITIZATION_MODE = false`
2. Navigate to "Ocean Sunset" post
3. The alert will execute automatically when comments load
## 4. Mitigation Strategy
The project implements a **defense-in-depth** approach with multiple layers of protection:
### 4.1 Mitigation Toggle
A configuration flag controls mitigation:
```javascript
const SANITIZATION_MODE = false; // Set to true to enable mitigation
```
### 4.2 Layer 1: Input Sanitization (DOMPurify)
#### 4.2.1 DOMPurify Library Integration
DOMPurify is loaded via CDN in `index.html`:
```html
```
#### 4.2.2 Input Sanitization Function
The `sanitizeInput()` function uses DOMPurify to sanitize user input before storage:
```javascript
function sanitizeInput(input) {
// Check if DOMPurify is available (loaded from CDN)
if (typeof DOMPurify !== "undefined") {
// DOMPurify: Removes dangerous HTML/scripts but allows safe content
// ALLOWED_TAGS: [] means no HTML tags allowed (strict mode)
return DOMPurify.sanitize(input, {
ALLOWED_TAGS: [], // No HTML tags allowed - treats everything as plain text
ALLOWED_ATTR: [], // No attributes allowed
});
} else {
// Fallback: Basic sanitization if DOMPurify fails to load
const tempDiv = document.createElement("div");
tempDiv.textContent = input; // textContent will auto escapes HTML
return tempDiv.innerHTML;
}
}
```
**How it works:**
- DOMPurify parses the input and removes all dangerous HTML elements and attributes
- With `ALLOWED_TAGS: []`, all HTML tags are stripped, leaving only plain text
- HTML entities are properly escaped (e.g., ` {
// Create elements programmatically to avoid XSS
const commentDiv = document.createElement("div");
commentDiv.className = "comment";
const authorDiv = document.createElement("div");
authorDiv.className = "comment-author";
authorDiv.textContent = comment.author; // textContent escapes HTML
const textDiv = document.createElement("div");
textDiv.className = "comment-text";
textDiv.textContent = comment.text; // textContent escapes HTML
const dateDiv = document.createElement("div");
dateDiv.className = "comment-date";
dateDiv.textContent = comment.date;
// Build DOM tree safely
commentDiv.appendChild(authorDiv);
commentDiv.appendChild(textDiv);
commentDiv.appendChild(dateDiv);
commentsContainer.appendChild(commentDiv);
});
}
```
**How it works:**
- `document.createElement()` creates DOM elements programmatically
- `textContent` property treats content as plain text and automatically escapes HTML
- `appendChild()` builds the DOM tree without parsing HTML strings
- No HTML/JavaScript can execute because content is never parsed as HTML
#### 4.3.2 Comparison: Vulnerable vs Safe
**Vulnerable (innerHTML):**
```javascript
container.innerHTML = `${userInput}`;
// If userInput = ""
// Result: Event handler executes โ (Script tag wouldn't work due to browser protection)
// If userInput = "alert('XSS')"
// Result: Script tag is stripped by browser, but event handlers still execute โ
```
**Safe (textContent):**
```javascript
const div = document.createElement("div");
div.textContent = userInput;
container.appendChild(div);
// If userInput = "alert('XSS')"
// Result: Displayed as text "alert('XSS')" โ
```
#### 4.3.3 Application in Display Logic
The safe display function is used when mitigation is enabled:
```javascript
// Refresh comments display
if (SANITIZATION_MODE) {
displayCommentsSafe(postId); // Safe: uses textContent
} else {
displayComments(postId); // Vulnerable: uses innerHTML
}
```
**Protection**: Even if malicious data somehow bypasses input sanitization, output sanitization prevents execution.
### 4.4 Defense-in-Depth Benefits
Using both layers provides:
1. **Redundancy**: If one layer fails, the other provides protection
2. **Multiple Attack Vectors Covered**: Protects against both stored and potential reflected XSS
3. **Future-Proof**: If code changes introduce new vulnerabilities, multiple layers reduce risk
4. **Best Practice**: Industry standard approach recommended by OWASP
### 4.5 Enabling Mitigation
To enable mitigation, change one line in `script.js`:
```javascript
// Change from:
const SANITIZATION_MODE = false;
// To:
const SANITIZATION_MODE = true;
```
When enabled:
- โ Input is sanitized using DOMPurify before storage
- โ Output uses safe DOM manipulation with `textContent`
- โ XSS payloads are neutralized at both layers
- โ Malicious scripts cannot execute
---
## 5. Testing the Mitigation
### 5.1 Test Procedure
1. **Enable Mitigation**: Set `SANITIZATION_MODE = true` in `script.js`
2. **Clear Storage**: Open browser console and run `localStorage.clear()`
3. **Reload Page**: Refresh the application
4. **Attempt Exploitation**: Try submitting XSS payloads:
- `` โ (Will execute)
- `` โ (Will execute)
- `alert('XSS')` โ (Won't execute - browser protection, but this doesn't mean the app is safe!)
5. **Verify Results**:
- Payloads should be displayed as plain text
- No JavaScript execution should occur
- Alert popups should not appear
### 5.2 Expected Results
**With Mitigation Enabled:**
- โ Malicious HTML is stripped or escaped
- โ Scripts do not execute
- โ Content displays as plain text
- โ Application functionality remains intact
**Without Mitigation:**
- โ Scripts execute automatically
- โ Alert popups appear
- โ Potential for cookie theft and session hijacking
## 7. Conclusion
This project successfully demonstrates:
1. โ **Vulnerability Implementation**: A realistic Stored XSS vulnerability in a blog application
2. โ **Exploitation**: Multiple attack vectors and payload examples
3. โ **Mitigation**: Defense-in-depth approach using:
- **Input Sanitization**: DOMPurify library for robust HTML sanitization
### 7.1 Key Takeaways
- **Stored XSS** is dangerous because payloads persist and affect all users
- **innerHTML** with user input is inherently dangerous
- **Defense-in-depth** provides multiple layers of protection
- **DOMPurify** is an industry-standard sanitization library
- **textContent** is safer than innerHTML for user-generated content
### 7.2 Tools and Techniques Summary
| Component | Technology/Tool | Purpose |
| -------------------- | --------------------- | ------------------------------ |
| Storage | localStorage API | Simulates database persistence |
| Sanitization | DOMPurify v3.0.8 | HTML sanitization library |
| Safe Rendering | textContent + DOM API | Prevents script execution |
| Vulnerable Rendering | innerHTML | Demonstrates XSS vulnerability |
| Language | JavaScript (ES6+) | Client-side logic |
| Markup | HTML5 | Page structure |
---