Skip to content

Stored XSS — Comment Section

Field Value
Platform PortSwigger Web Security Academy
Vulnerability Stored Cross-Site Scripting (XSS)
Difficulty Apprentice
Injection Point Comment field in blog post comment section
Goal Inject a script that executes for every visitor to the page

Phase 1 — Reconnaissance

We find a blog post with a comment section. Testing each field for injection. The email and website fields have client-side format validation — they reject invalid formats before the form can be submitted. Client-side validation is not a security control: it only runs in the browser and can be bypassed via Burp or by removing validation attributes in DevTools. Server-side validation is what matters.


Phase 2 — Exploitation

Testing the comment field with a script payload:

<script>alert("hola");</script>

Filling in valid values for the remaining fields and posting the comment:

Screenshot
Screenshot

The thank you page appeared. Navigating back to the blog post:

Screenshot

Two alerts fired — the comment field is confirmed vulnerable. The script is now stored in the database and executes for every user who visits the page.

Screenshot

The name field rendered our payload as visible text rather than executing it — the name field is HTML-escaped. The comment field is not. Not all fields on the same form are equally vulnerable: always test every field independently, as partial sanitization is common.

Two alerts fired because the payload was stored once but the page rendered it in two places — once in the comment body and once wherever else the comment content appeared on the page.


Conclusion

  1. The comment section form had client-side validation on the email and website fields — bypassed trivially since client-side validation is not a security control.
  2. Injecting <script>alert("hola");</script> into the comment field and submitting persisted the payload in the database.
  3. Returning to the blog post triggered two alert executions — the payload fired in every rendering location, for every visitor.
  4. The name field was correctly HTML-escaped; the comment field was not — confirming partial sanitization and the importance of testing all fields independently.

Reflected vs. Stored XSS — The Key Difference

Reflected XSS Stored XSS
Where payload lives In the URL / HTTP request In the database
When it executes Only when victim visits the attacker's crafted URL Every time any user views the affected page
Who is affected Only users tricked into clicking the malicious URL Every visitor — automatically
Attacker involvement after setup Must deliver the URL to each victim None — payload is already on the site
Severity Medium High

With reflected XSS, an attacker has to trick each victim individually into clicking a link. With stored XSS, the payload is embedded in the site itself — the attacker submits it once and every subsequent visitor is attacked automatically, including administrators.

Stored XSS in a comment section that administrators moderate is particularly dangerous: the admin visits the page to review comments, the script executes in their browser with their session — which may have elevated privileges — and the attacker gains admin-level access without the admin doing anything beyond viewing the page.


Key Concepts

Stored XSS persists indefinitely — unlike reflected XSS, no crafted URL is needed after the initial submission. The payload fires for every visitor until it is removed from the database.

Client-side input validation is not a security control — it only runs in the browser. Bypassing it via Burp or DevTools allows arbitrary values to be submitted. The only validation that counts is server-side.

Not all fields on the same form are equally vulnerable — the name field escaped output correctly; the comment field did not. Partial sanitization is common. Always test every input field independently.

Two alerts fired because the comment content rendered in two places — the payload was stored once but the page displayed it in multiple locations. Each rendering point is an independent execution of the stored script.