Self XSS to Stored XSS



      Hey Hackers ,
      My name is Parth Narula, and I'm thrilled to share an in-depth article on how I successfully chained a Self-XSS into a Stored XSS, ultimately leading to mass account takeover across the entire platform.

      We're all familiar with XSS — whether it's Reflected, Stored, Blind, DOM-based, or even Self-XSS. Often, we discover XSS in places like profile fields, but struggle to escalate the impact beyond our own account. In today's article, we’ll dive into how I converted a limited Self-XSS into a critical Stored XSS, affecting every user on the platform. Let’s break down the chain and the mindset behind it.


    1. Self XSS

      Okay, so let’s start with the basics. Self-XSS refers to scenarios where malicious JavaScript is executed only in the attacker's own context — meaning only the person who injects the payload can trigger it. You test it, see it fire, and assume: “Ah, just Self-XSS, nothing serious.” But that’s where most people make a big mistake.

      You might inject your payload into fields like name, address, bio, or description, thinking only you can view or trigger those fields — so it must be self-contained. But what if those fields are actually publicly accessible across the platform? What if they're rendered in admin dashboards, public profiles, or notifications? That’s where the real game begins — and Self-XSS silently transforms into a critical Stored XSS.



    2. Discovery & Esclation

      While signing up, I tested the artist name field with basic HTML, which reflected back in a confirmation email, confirming HTML Injection. Later, I found that editing the same field triggered Self-XSS in my profile settings.

      But when I enabled the Collaboration feature, the payload became publicly visible, turning the Self-XSS into a Stored XSS — executing for all users, including admins.
      So what started as a harmless Self-XSS turned into a full-blown Stored XSS, executing across all user sessions via a application feature. And just like that — a low-severity HTML Injection escalated to a critical vulnerability.



    i.) Discovery

      It all started with a simple signup test — nothing fancy, just playing around with some basic payloads to see what sticks.


    1. Step I started at the signup page: https://redacted/sign-up. Out of habit, I dropped a basic HTML injection payload into the artist name field — something simple but mixed with a touch of SSTI and SQLi: "'<h1>${{7*7}}</h1>

    2. Step A few seconds later, I got a confirmation email... and boom — the injected HTML rendered right inside the email body. That’s when I knew the artist name field was vulnerable to email-based HTML injection. But I wasn’t done yet — time to dig deeper.

    3. Step I visited my profile settings page at https://redacted/artists/settings/my-profile, replaced the artist name with a basic XSS payload: <img/src/x onerror=prompt(document.cookie)> Clicked save, refreshed the page — and the script popped right there in my own session. So it was a classic Self-XSS, limited to my account. as was normal self xss.




    ii.) Esclation

      So far, we had an email HTML injection and a Self-XSS — cool, but not critical. But then it got interesting.


    1. Step I checked my public profile at https://redacted/artists/{username}/profile to see if the payload showed up there — nothing. No execution.

    2. Step While scrolling through my account settings, I noticed a feature called "Open to Collaboration", which was set to “Not interested”. I changed it to “Remotely or in person” just to see what changes.

    3. Step After updating that setting, I revisited my public profile and saw a new icon (people group) appear at the top-right. Curious, I clicked it — and bam, the payload fired.
      Not just for me — it executed for anyone who viewed my profile. That includes logged-in users, unauthenticated users, and even admins.

    https://api.redacted.co/v1/artists/:id
    {
    "changeType":"PROFILE",
    "fullname":"PAYLOAD_HERE",
    "collaborationStatusId":"REMOTE_OR_IN_PERSON"
    }




    4. Tips and Techniques


      Don’t ignore low-impact injection: Like HTML Injection or Self-XSS. These often look harmless but can reveal deeper flaws in how user input is handled — especially when reflected in places like emails or profiles.

      Always test input across different render contexts: Emails, profiles, dashboards, etc. A field vulnerable in one area might be reused elsewhere in ways you don’t expect.

      Never trust what looks private: Just because a payload fires in your own view doesn’t mean it’s not exposed somewhere else — like public pages or admin views.

      Utilize app features: Small app features (like "Open to Collaboration") can change where data appears — and that can turn a Self-XSS into a critical Stored XSS if the input gets reflected somewhere shared.

      Impact is everything A bug isn’t truly low-severity until you’ve tested its full reach.



    5. Mitigation

      If you’re on the defensive side, you’ll want to lock these doors:

      Block dangerous MIME types or tags in forms: Disallow script tags, event handlers (onerror, onload, etc.), and dangerous attributes during form submission — especially for public-facing profile fields.

      Secure email rendering: Avoid injecting raw user input directly into email templates. Encode or sanitize all dynamic fields to prevent email HTML injection.

      HTML sanitization on input or output: If rich text is allowed, use strict sanitizers (e.g., DOMPurify, bleach) to strip out tags, attributes, or scripts that shouldn't be there. Never rely on blacklists.

      Regular Testing: Periodic security assessments are essential to catch any weak points before attackers do. In this ScriptJacker can help you with its flexible pentesting offers.



    6. Conclusion


      So, what started off as a harmless self-triggered XSS ended up being a critical vulnerability impacting every user on the platform. The key takeaway? Always dig deeper — even small bugs can lead to big impact.

      I hope you learned something new from this write-up!
      ScriptJacker also offers professional pentesting services — feel free to share your thoughts via the Contact page or Email, or reach out if you'd like to contribute an article. If the topic’s solid and insightful, I’ll be happy to publish it under your name!