Stored XSS Lab: Plant a Comment That Runs for Every Visitor

✨ AI Summary
DevBlog lets readers leave comments, saves them, and shows them to every visitor. That is what comments are for. The problem is how it shows them: as raw HTML. Write a comment that contains markup instead of words, and the site will serve your code to every person who reads the post, without you sending a single link.
Lab at a glance: Beginner · 60 XP · about 10 minutes · runs in your browser, no signup or setup. Try it yourself first; the full solution is behind a spoiler below.

What this lab teaches

Stored XSS, also called persistent XSS, is the same bug as reflected XSS with one big difference: the site saves your payload. Every time the page loads, it reads the stored comment and writes it into the page as HTML, so the script runs for every visitor.

That makes it more dangerous. The attacker does not need to trick anyone into clicking a link. Victims just have to visit a normal page on a site they trust.

How DevBlog's comments work

Comments are saved to the page’s storage and re-rendered on every visit. The rendering code reads each comment body and inserts it with innerHTML, with no escaping. The lab is solved when your stored comment calls the lab’s solve function, and it should still fire after you refresh the page.

The attack approach

  • Post a normal comment first and confirm it is saved and shown after a refresh.
  • Post a comment with a little harmless HTML, like bold text, to confirm markup is rendered rather than shown as text.
  • As in the reflected XSS lab, a script tag will not run through innerHTML. Use an element with an event handler instead.
  • Refresh the page. If the payload fires again, it is truly stored.

Full walkthrough (spoiler)

Stuck after a few attempts? Open the steps below. Solving it yourself first is worth more XP, and more learning.

Show the step-by-step solution
  1. Write a comment containing an image tag whose source is deliberately broken.
  2. Add an error handler to that image that calls the lab’s solve function with the flag from the objective.
  3. Post the comment. The image fails to load and the handler runs straight away.
  4. Refresh the page. The comment is loaded from storage, rendered again, and the handler fires again. That persistence is what makes it stored XSS.

Why it works

The site trusts its own database. Developers often escape input on the way in, or forget to escape it on the way out, assuming anything already saved is safe. But stored data is just user input that has been waiting. When it is written into the page as HTML, it runs with the site’s full authority for whoever is viewing, including moderators and admins who open the comment queue.

Core principleTreat stored data as untrusted. Escape it every time you output it, not once when it comes in.

Where this happens in the real world

The best-known example is the Samy worm of 2005. A stored XSS in MySpace profiles added its author as a friend to everyone who viewed an infected profile, and copied itself onto their profile too. It spread to over a million accounts in about a day. Stored XSS in admin panels is especially valuable to attackers, because a payload that fires for an administrator can create accounts or change settings.

How to defend against it

  • Escape on output, every time, using context-aware encoding for HTML, attributes and JavaScript.
  • If you must allow rich text, use a proven HTML sanitiser such as DOMPurify with a strict allowlist, not hand-written filters.
  • Add a Content Security Policy that blocks inline event handlers.
  • Mark session cookies HttpOnly so a script cannot read them directly.
  • Review the admin side too. Moderation screens that render user content are prime targets.
Mr Elite tip: In real bug bounty work, stored XSS usually pays more than reflected XSS because it needs no user interaction. Always note who can see your payload: just you, other users, or staff. That is what decides the severity.

Try it, then go further

Reading about it is the easy part. Open the lab, try your own approach before peeking at the spoiler, and see how many attempts it takes.

❓ Frequently asked questions

What is stored XSS?
A cross-site scripting bug where the site saves attacker input, such as a comment, and later shows it to other users as HTML, so the attacker's script runs in every viewer's browser.
Why is stored XSS more dangerous than reflected XSS?
It needs no crafted link or user interaction. Anyone who views the affected page runs the payload, including administrators.
Can I allow some HTML in comments safely?
Yes, with a well-maintained sanitiser library and a strict allowlist of tags and attributes. Never write your own filter.
What should I try next?
The SVG sanitiser bypass lab, then the markdown rendering injection lab, which shows the same bug class through an AI chatbot.
⚡
Join free to earn XP for reading this article Track your progress, build streaks and compete on the leaderboard.
Join Free
Lokesh N. Singh aka Mr Elite
Lokesh N. Singh aka Mr Elite
Founder, Securityelites · AI Red Team Educator
Founder of Securityelites and creator of the SE-ARTCP credential. Working penetration tester focused on AI red team, prompt injection research, and LLM security education.
About Lokesh ->

Leave a Comment

Your email address will not be published. Required fields are marked *