Stored XSS — Persistence and Propagation
What Is Stored XSS?
Stored Cross-Site Scripting (also called persistent XSS or Type II XSS) occurs when an attacker injects malicious script into a data store — a database, a comment system, a message board, a user profile — and that script is subsequently served to every user who visits the affected page. Unlike reflected XSS, which requires the victim to follow a crafted link and fires only once, stored XSS is embedded in the application itself and executes automatically every time any user loads the page containing it.
This persistence is what makes stored XSS one of the most dangerous vulnerability classes in web security. A single successful injection can silently attack thousands of users over days, weeks, or months before it is discovered and removed.
How Stored XSS Differs from Reflected XSS
With reflected XSS, the malicious script travels in the HTTP request (typically a URL parameter) and is immediately reflected back in the HTTP response. The payload exists only for the lifetime of that single request/response cycle. The attacker must deliver the crafted URL to each victim individually — through phishing, shortened links, or social engineering.
Stored XSS eliminates this requirement entirely. The payload is written once into the server's data store. From that point forward, the server itself becomes the delivery mechanism — it faithfully serves the malicious script to every subsequent visitor with no further action required from the attacker.
Why Stored XSS Is More Dangerous
- Scale: Every user who loads the affected page is a victim. A popular blog post, a product review, or a public forum thread can expose thousands of users within hours.
- No victim interaction: The victim does not need to click a link. Merely loading the page triggers the payload.
- Elevated trust: The script executes in the same origin as the legitimate application. Users — and browsers — have no reason to be suspicious.
- Longevity: The payload persists until an administrator identifies and removes it. Attack campaigns can continue undetected for extended periods.
- Admin targeting: If an administrator reviews flagged comments or moderation queues, a stored XSS payload is executed in a privileged session, potentially yielding admin-level access in a single automated step.
The Attack Chain: Inject, Visit, Steal, Hijack
This lab walks through a complete four-phase attack chain.
Phase 1 — Injection: The attacker identifies a form field (in this case a blog comment box) where user-supplied input is stored and later rendered without adequate output encoding. The attacker submits a <script> tag or an event-handler attribute containing JavaScript that reads document.cookie and transmits it to an attacker-controlled endpoint.
Phase 2 — Victim Visits: A legitimate user — in this scenario a victim with an active admin session — loads the page containing the comment. The browser parses the HTML and executes the injected script as if it were part of the legitimate application. The script runs under the origin of the target site, granting it full access to cookies, storage, and the DOM.
Phase 3 — Cookie Exfiltration: The script reads the session cookie via document.cookie and sends it to the attacker's collection server, typically via a fetch() request, an XMLHttpRequest, or an <img> tag whose src attribute is set to a URL containing the cookie value as a query parameter.
Phase 4 — Session Hijacking: The attacker retrieves the captured cookie from the collection server, injects it into their own browser, and issues requests to the application. The server sees a valid session token and grants access as the victim — without requiring the victim's credentials and without triggering any login alert.
Understanding this full chain — not just the injection step — is essential for building effective defences, because each phase represents an independent point where the attack can be broken.