Stored Cross-Site Scripting (Persistent XSS) occurs when malicious input is stored (in a database, localStorage, file, etc.) and later displayed to users without proper sanitization. This is considered the most dangerous type of XSS because:
Post these as comments to see the vulnerability in action:
<img src=x onerror=alert('Stored XSS')>
<script>alert('This XSS persists!')</script>
<img src=x onerror="alert('Executed on every page load!')">
<h1 style="color: red;">DEFACED!</h1>
Notice: These payloads will be stored in localStorage and execute every time the page loads, demonstrating persistence!
Vulnerable Code:
// โ VULNERABLE: Storing and displaying user input with innerHTML
function postComment() {
const comment = document.getElementById('input').value;
// Store in localStorage (or database in real app)
let comments = JSON.parse(localStorage.getItem('comments') || '[]');
comments.push({text: comment, date: new Date()});
localStorage.setItem('comments', JSON.stringify(comments));
// Display using innerHTML - DANGEROUS!
displayElement.innerHTML = comment;
}
The problem: User input is stored without sanitization and displayed using innerHTML,
allowing malicious scripts to persist and execute for all users.
Secure Code:
// โ
SECURE: Sanitize before storing and use textContent
function postComment() {
const comment = document.getElementById('input').value;
// Sanitize input before storing
const sanitized = DOMPurify.sanitize(comment);
// Or escape HTML
const escaped = escapeHtml(comment);
// Store sanitized version
localStorage.setItem('comments', JSON.stringify([escaped]));
// Display using textContent
displayElement.textContent = escaped;
}
This lab uses localStorage to simulate a database. In a real application,
comments would be stored in a backend database. The vulnerability and prevention techniques
are the same - never trust stored data and always sanitize/encode when displaying.
Try this: Post a malicious comment, then reload the page. Notice how the XSS payload executes again! This demonstrates the persistent nature of Stored XSS.