Stored XSS
The attacker plants a payload in the database. Every visitor who loads the affected page executes it — comments, reviews, profiles are the classic delivery channels.
The attacker plants a payload in the database. Every visitor who loads the affected page executes it — comments, reviews, profiles are the classic delivery channels.
Stored XSS — also called persistent or Type I XSS — occurs when an attacker injects malicious script into a data store that the application later serves to other users. Unlike reflected XSS, the payload persists on the server and executes in every victim's browser without requiring a crafted link. Comment sections, user profiles, and message boards are the most common targets.
The danger of stored XSS lies in its amplification. A single injected payload is written to a database or file and served to every subsequent visitor. No phishing is needed — the attacker simply submits the payload through a form or API, and the application becomes a delivery vehicle for the attack. The payload executes in the security context of the application, meaning it can read cookies, make authenticated requests, and modify the DOM on behalf of every victim.
Comment sections are the canonical vector. A comment form that stores user-submitted HTML and renders it on a public page without escaping allows an attacker to inject a <script> tag that executes for every reader. Profile fields — "About me" sections, display names, and bios — are equally dangerous because they are rendered on multiple pages across the site.
Post a comment below. In vulnerable mode, the comment is rendered unescaped — any HTML you include executes for every viewer. Switch to safe mode to see how output encoding prevents script execution while preserving the displayed text.
Welcome to the comment board! Try posting a message.
In October 2005, Samy Kamkar discovered a stored XSS vulnerability in MySpace's profile page. MySpace had filtered <script>, <body>, andonclick but missedonmouseover combined with CSSbackground: url(javascript:…). Samy crafted a profile that, when viewed, added the viewer as a friend and copied the payload to the viewer's own profile. Within 20 hours, over one million MySpace users were infected. The worm was so aggressive that MySpace had to shut down its servers temporarily.
The Samy worm remains the definitive case study in stored XSS because it demonstrated self-propagation without any server-side exploit. The vulnerability was a single unescaped profile field, and the effect was a platform-wide outage. It also led to the first felony conviction for a social-networking worm under the Computer Fraud and Abuse Act.
// VULNERABLE — stores and renders raw HTML
app.post('/comment', (req, res) => {
db.insert('comments', { body: req.body.comment });
});
app.get('/post/:id', (req, res) => {
const comments = db.select('comments');
let html = comments.map(c => '<div>' + c.body + '</div>');
res.send(html); // raw HTML in response
});
// SAFE — output-encode at render time
app.get('/post/:id', (req, res) => {
const comments = db.select('comments');
let html = comments.map(c =>
'<div>' + escapeHtml(c.body) + '</div>'
);
res.send(html);
});The standard defence against stored XSS is to apply context-aware output encoding when rendering data, not when storing it. Storing the raw input preserves the original data and lets the presentation layer handle escaping correctly based on the output context — HTML body, attribute, JavaScript, or CSS. This approach avoids double-encoding and data loss that input filtering would cause.
Server-side template engines like React JSX, EJS, and Handlebars auto-escape HTML context by default, but developers must avoid APIs that bypass escaping, such as dangerouslySetInnerHTML in React or | safe in Jinja2. In cases where HTML is intentionally allowed (e.g. rich text editors), use a sanitisation library like DOMPurify to strip dangerous tags and attributes.
1.Why is stored XSS considered more dangerous than reflected XSS?
2.What is the best practice for defending against stored XSS?
3.How did the Samy worm propagate on MySpace?