Hey there!๐Ÿ˜

Life has taught me one important lesson: "Disabled" rarely means disabled. It usually means hidden. And hidden things have a bad habit of leaking secrets.

This is the story of a feature that was supposedly turned off, a backend that never got the message, and how a greyed-out button quietly led to one of my highest-impact findings.

๐Ÿง  It Started Like Any Normal Recon Day

Nothing fancy. No zero-days. Just mass recon, half-empty coffee, and that familiar itch to poke things that look a little too clean.

The application was modern. React frontend. Clean UI. Lots of toggles and "Coming Soon" labels. One feature in particular caught my eye โ€” Advanced Reports.

The button was disabled. Greyed out. Tooltip said something like "This feature will be available soon."

Most users would stop there.

Bug bounty hunters don't.

๐Ÿ•ต๏ธ Watching the App Talk Too Much

Instead of clicking around, I opened DevTools and watched the network traffic while the page loaded.

Even though the feature was "disabled," the frontend was still making calls like:

GET /api/v2/feature-flags
GET /api/v2/user/permissions
GET /api/v2/reports/config

That was my first red flag.

If the backend is still sending feature configs, it usually means the logic exists. The UI is just pretending it doesn't.

And pretending is not security.

๐Ÿšจ The Moment Things Feltโ€ฆ Wrong

I noticed a request related to exporting reports:

POST /api/v2/reports/export

The frontend only used it for basic exports. The payload looked harmless:

{
  "type": "basic",
  "format": "csv"
}

Out of curiosity (and bad intentions), I changed one word.

{
  "type": "advanced",
  "format": "json",
  "include": ["users", "roles", "audit_logs"]
}

I hit send.

No error. No access denied. No "feature disabled" message.

Just a 200 OK and a download prompt.

That's when I stopped smiling.

๐Ÿ’ฃ What Came Back Wasn't "Coming Soon"

The exported file contained things I absolutely should not have had access to:

  • User email addresses
  • Internal role mapping
  • Permission flags
  • Audit metadata
  • Feature toggles meant for enterprise tenants

This wasn't a broken UI bug. This was a backend authorization failure hiding behind a disabled button.

The frontend said no. The backend said "sure, why not."

None
GIF

๐Ÿงฉ The Real Issue (And Why This Happens So Often)

The root cause was painfully familiar:

  • Feature flags enforced only in the frontend
  • Backend trusted whatever the client sent
  • No server-side entitlement validation

Someone assumed users wouldn't call endpoints that the UI doesn't expose.

That assumption pays bug bounty hunters very well.

๐Ÿ” Digging Deeper: Backend / Frontend Mismatch

Once I confirmed the backend didn't care about feature access, I started testing parameters the frontend never touched.

For example:

Frontend request:

GET /api/v2/reports/list?limit=10

Backend also accepted:

GET /api/v2/reports/list?limit=10&scope=global

No role check. No tenant validation.

scope=user returned my data. scope=global returned everyone's.

At this point, the impact was already high. But the app had one more mistake waiting for me.

๐Ÿง  When Cache Poisoning Joined the Party

The reports endpoint was behind a CDN.

I checked the headers:

Cache-Control: public, max-age=600
Vary: X-Feature-Flag

That made my stomach drop.

Why?

Because the backend trusted client-controlled headers to decide feature behavior.

So I tried this:

X-Feature-Flag: advanced_reports=true

Then requested:

GET /api/v2/reports/list?scope=global

The response โ€” full of sensitive data โ€” was cached.

Meaning other users could now receive poisoned responses they were never supposed to see.

That's when this turned from "nice logic bug" into a serious cross-user data exposure via web cache poisoning.

๐Ÿงช Clean Proof of Concept (Realistic Flow)

1๏ธโƒฃ Identify disabled feature in UI Look for:

  • Greyed-out buttons
  • "Coming soon" labels
  • Feature toggles in JS files

2๏ธโƒฃ Extract backend endpoints

grep -R "/api/" build/

Or just watch XHR requests in DevTools.

3๏ธโƒฃ Replay the request manually

curl -X POST https://target.com/api/v2/reports/export \
  -H "Authorization: Bearer <USER_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "type":"advanced",
    "include":["users","roles","audit_logs"]
  }'

4๏ธโƒฃ Poison the cache

curl https://target.com/api/v2/reports/list?scope=global \
  -H "X-Feature-Flag: advanced_reports=true"

๐Ÿ“ˆ Impact Summary (Why This Paid Well ๐Ÿ’ฐ)

  • Feature flag bypass
  • Backend authorization failure
  • Access to enterprise-only data
  • Web cache poisoning
  • Cross-user sensitive data exposure

No fancy exploit chains. Just logic, patience, and a backend that trusted the UI too much.

Connect with Me!

  • Instagram: @rev_shinchan
  • Gmail: rev30102001@gmail.com

#EnnamPolVazhlkai๐Ÿ˜‡

#BugBounty, #CyberSecurity, #InfoSec, #Hacking, #WebSecurity, #CTF