Hi, let me introduce myself — I'm Kanishka Khandelwal. I'm currently working as an Associate Security Engineer, and apart from my day job, I spend most of my time doing bug bounty. I enjoy testing different applications, understanding how they work behind the scenes, and finding those small things that don't look right at first. Most of the time, it feels like there's nothing there… but I just keep digging until something finally clicks.
I was testing a SaaS platform that had a Responsible Disclosure Program. Let's call it example.com.
The platform offered multiple subscription tiers, including a paid Enterprise plan, which unlocked advanced features and integrations.
Initial Observation
I created a normal account and logged in.
As expected:
- My account had a trial plan
- I was restricted from accessing premium features
Everything looked properly implemented at first.
So I tried the usual things:
- Parameter tampering
- Changing request values
- Exploring hidden endpoints
But honestly… nothing worked. At this point, I was stuck.
The Turning Point
Instead of blindly sending payloads, I opened Burp Suite and started analyzing the application flow more carefully.
While navigating through the app, I found an API endpoint:
GET /api/plan HTTP/2
Host: api.example.comExcessive Data Exposure
The response of this API was interesting:
HTTP/2 200 OK
{
"status": true,
"plans": [
{
"displayName": "Trial",
"price": 0,
"features": [
"xx",
"xx",
"xx",
"xx"
]
},
{
"displayName": "Enterprise",
"price": xxx,
"features": [
"xx",
"xx",
"xx",
"xx"
]
},
{
"displayName": "xxxxx",
"price": xxx,
"features": [
"xx",
"xx",
"xx",
"xx"
]
},
{
"displayName": "xxxx",
"price": xxx,
"features": [
"xx",
"xx",
"xx",
"xx"
]
}
]
}This endpoint exposed:
- All subscription plans
- Internal plan structure
- Features of each plan
This was clearly an Excessive Data Exposure [Information disclosure] issue.
At this point, I had a thought: If the frontend is getting all plan data… maybe it's trusting it too..??
Digging Deeper
I logged out, then logged in again with interception enabled in Burp Suite.
While forwarding requests step-by-step, the request handing the plan appeared :
GET /api/initial-data HTTP/2
Host: api.example.comThis time, I intercepted the response instead of the request.
Original Response (Simplified)
{
"user": {
"plan": {
"displayName": "Trial",
"features": ["basic_feature_1","basic_feature_2"]
}
},
"featureFlags": ["basic_feature_1","basic_feature_2"]
}Exploitation
Inside Burp Suite, I modified the response before forwarding it.
Step 1: Replace Plan Data
I replaced the trial plan with enterprise plan data (copied from exposed API):
"plan": {
"displayName": "Enterprise",
"price": xxx,
"features": ["xx","xx","xx","xx"]
}Step 2: Modify Feature Flags
Then I added enterprise-level features inside feature flags:
"featureFlags": [
"basic_feature_1",
"basic_feature_2",
"advanced_feature_1",
"advanced_feature_2",
"enterprise_only_feature"
]Final Step
- Forwarded the modified response
- Turned off interception
What Happened Next
The UI refreshed…
And just like that — my account was now showing Enterprise Plan.
No payment. No upgrade request. No backend validation.
Impact
With this unauthorized upgrade, I was able to:
- Access enterprise-only features
- Enable restricted integrations
- Use premium functionalities
- Bypass payment completely
All of this:
- Without paying
- Without server-side validation
Root Cause
The issue exists because:
- The application trusts client-side modified responses
- No server-side validation for plan enforcement
- Authorization logic depends on frontend state
- Feature flags are controlled via response data
Why This is Critical
This is not just a small bug.
It leads to:
- Revenue loss
- Privilege escalation
- Broken access control
This falls under:
- Business Logic Vulnerability
- Broken Access Control (OWASP Top 10)
Recommended Fix
- Never trust client-side data (including responses)
- Enforce plan validation strictly on the backend
- Implement server-side authorization checks
- Do not rely on feature flags from client responses
Final Thoughts
This bug taught me something important:
Sometimes the vulnerability is not in the request you send… It's in the response you decide to trust.
Bonus Insight
When you feel stuck:
- Stop sending payloads blindly
- Observe HTTP history in Burp Suite
- Understand how the application behaves
Because sometimes… the application itself tells you where it's broken.
Reward…???
Interestingly, this issue wasn't limited to just one platform. I've seen similar behavior across multiple SaaS applications and responsibly disclosed them.
In many cases, the impact was somewhat limited — for example, refreshing the page would revert the plan back to its original state, indicating weak client-side enforcement but no persistence.
However, in this particular case, the behavior was different.
The changes made through response manipulation were persisted in the application state:
- The upgraded plan remained active even after page refresh
- Features continued to work without reverting
- Repeating the same interception during login would restore the manipulated state again
This indicates a deeper trust issue, where the application not only relied on client-side responses but also failed to properly revalidate state across sessions.
Despite this, such issues are often treated as "functional bugs" rather than security vulnerabilities — which highlights how underestimated business logic flaws and client-side trust issues still are in many real-world applications.
Thank you for reading. Feel free to share your thoughts in the comments or connect with me on LinkedIn: https://www.linkedin.com/in/kanishka-khandelwal-a49050263/