Introduction

In this write-up, I will demonstrate how I solved the Stored XSS into HTML context with nothing encoded lab on PortSwigger Academy. This lab highlights a critical vulnerability where user-supplied input (in this case, a blog comment) is stored on the server and later executed in the browser of anyone who views the page.

The Vulnerability

Unlike Reflected XSS, Stored XSS occurs when the malicious script is permanently stored on the target server (e.g., in a database). When a victim navigates to the affected page, the browser retrieves the script and executes it.

Steps to Reproduce

1. Initial Exploration (Recon)

I started by exploring the website and mapping out its functionality. I found a blog post with a comment section at the bottom. This is a common place for Stored XSS because comments are saved on the server and displayed to all visitors.

2. Testing Input Handling

First, I submitted a normal comment to see how the application renders it. I noticed that the comment was displayed on the page without any apparent filtering or security checks on the input fields.

3. Injecting the Payload

To test for Stored XSS, I entered a simple JavaScript payload into the comment text area:

Payload:

<script>alert(1)</script>
None

Execution and Persistence

After clicking "Post Comment," I went back to the blog post. The browser immediately executed the script, and an alert box popped up.

Because this is a Stored vulnerability, every time the page is refreshed or visited by another user, the script will execute automatically because it is now part of the page's HTML stored on the server.

None

Payload Used:

<script>alert(1)</script>

Impact

Stored XSS is highly dangerous because:

  • It is persistent: It affects every user who visits the page.
  • It can be used to steal session cookies, perform actions on behalf of other users, or spread "worms" through the platform.
  • The victim doesn't need to click a malicious link; simply viewing the page is enough.

Remediation (How to Fix)

To prevent Stored XSS, developers must:

  1. Output Encoding: Always encode user-generated content before rendering it in the HTML (e.g., convert < to <).
  2. Input Validation: Use a strict allow-list for characters allowed in input fields.
  3. Use a Content Security Policy (CSP): To prevent the execution of unauthorized scripts.

Conclusion

This lab successfully demonstrates the persistence of Stored XSS. It serves as a reminder that any data stored in a database and later displayed to users must be handled with extreme caution.

Happy Hacking!