June 20, 2026
From a Simple Input Field to Stored XSS — A Realistic Bug Bounty Journey
Introduction
Ankitsingh
2 min read
Introduction
While testing a web application during a bug bounty engagement, I came across a Stored Cross-Site Scripting (Stored XSS) vulnerability hidden inside a feature that looked completely harmless.
At first glance, it was just another profile/customization input field. Nothing unusual. But after spending some time understanding how the application handled user-generated content across different sections, I noticed something interesting:
The application sanitized input inconsistently.
That small inconsistency eventually led to a Stored XSS vulnerability capable of executing JavaScript whenever another user viewed the affected page.
This blog walks through the discovery process, methodology, payload testing, impact analysis, and remediation recommendations.
Target Recon
The target application allowed users to:
- Edit public profile information
- Share posts/comments
- Customize certain sections using rich text inputs
- Interact with other users through collaborative features
During testing, I focused specifically on:
- Reflection points
- Markdown/rendering behavior
- HTML entity handling
- Input sanitization inconsistencies
- Stored content rendered across multiple pages
Most parameters were properly escaped.
But one section caught my attention.
A user-controlled input was rendered inside the frontend without strict sanitization after being stored in the backend database.
That became the attack surface.
Initial Testing
I started with basic payloads:
<script>alert(1)</script><script>alert(1)</script>The application blocked the payload.
Next, I tried:
<img src=x onerror=alert(1)><img src=x onerror=alert(1)>The payload was stored successfully, but execution did not occur.
At this point, it looked partially filtered.
Instead of giving up, I began testing:
- Different HTML tags
- Event handlers
- Encoded payloads
- SVG-based vectors
- Nested HTML structures
After multiple attempts, I noticed the application removed certain dangerous keywords but failed to sanitize SVG event handlers properly.
That changed everything.
Finding the Bypass
After several payload variations, the following payload executed successfully:
<svg onload=alert(document.domain)><svg onload=alert(document.domain)>The payload:
- Was accepted by the backend
- Stored in the database
- Rendered unsanitized when the page loaded
- Executed automatically for anyone viewing the affected content
This confirmed a Stored XSS vulnerability.
Why This Happened
The core issue was:
- Input validation existed
- But output sanitization was incomplete
The application attempted blacklist-based filtering instead of proper context-aware escaping.
As a result:
- Certain tags were blocked
- Some attributes were filtered
- But SVG-based execution vectors remained possible
This is a common mistake in modern applications relying on partial sanitization logic.
Escalating the Impact
A simple alert box is never the real impact.
To demonstrate realistic exploitation, I analyzed what an attacker could actually do.
Potential attack scenarios included:
- Session hijacking
- Performing actions on behalf of victims
- Account takeover via token theft
- Phishing overlays inside the application
- Internal admin panel compromise
- Wormable payloads affecting multiple users
If an administrator viewed the malicious content, the impact could become significantly more severe.
Proof of Concept Flow
Step 1
Create or edit content inside the vulnerable input field.
Step 2
Insert the malicious SVG payload.
Step 3
Save the content.
Step 4
Whenever another user opens the affected page, the JavaScript executes automatically.
Root Cause Analysis
The vulnerability existed because:
- User input was trusted too early
- Sanitization rules were incomplete
- Dangerous HTML contexts were still allowed
- Output encoding was not enforced consistently
The backend relied heavily on frontend filtering, which is never sufficient for security-sensitive rendering.
Security Recommendations
1. Context-Aware Output Encoding
Always escape user-controlled data before rendering it in HTML, JavaScript, or attribute contexts.
2. Use Trusted Sanitization Libraries
Avoid custom blacklist filters. Use mature sanitization libraries designed for XSS prevention.
3. Block Dangerous Tags
Restrict:
<script><svg><iframe>- Inline event handlers
- JavaScript URLs
4. Implement CSP
A strict Content Security Policy (CSP) can reduce XSS impact significantly.
5. Validate on Both Frontend and Backend
Client-side filtering alone should never be trusted.
Final Thoughts
One of the biggest lessons from bug bounty hunting is this:
The most dangerous vulnerabilities often hide behind ordinary functionality.
This wasn't discovered through automation or heavy tooling.
It came from:
- Patience
- Manual testing
- Understanding rendering behavior
- Thinking like an attacker
Stored XSS vulnerabilities remain extremely impactful because they target trust between users and the application itself.
Sometimes, a single overlooked rendering path is all it takes.
Thanks for reading. Follow me for more of this content. Happy hacking!