(Beyond IDOR – A Real-World Authorization Failure Case Study)
Disclaimer
This write-up is strictly educational.
The application, endpoints, roles, and identifiers are fully anonymized.
No real system was harmed, and this content is meant to help developers and security learners understand how broken access control happens in the real world.
Why This Post Exists (Read This First)
Most people think Broken Access Control = IDOR.
That’s wrong.
IDOR is just one symptom.
Broken Access Control is a mindset failure:
“The user won’t try that.”
This post shows how I exploited role-based access control failures, hidden endpoints, and frontend-only restrictions — without touching admin credentials.
What Is Broken Access Control? (Quick but Important)
Broken Access Control happens when:
- Users can perform actions outside their intended permissions
- The backend fails to enforce authorization
- The frontend is treated as a security boundary (🚫)
OWASP Rank:
A01:2021 – Broken Access Control
This is the #1 web vulnerability globally.
Target Overview (Anonymized)
- Type: SaaS-style web application
- Roles:
- User
- Moderator
- Admin
- Features:
- Dashboard
- User management
- Reports
- Auth: JWT-based authentication
- Frontend: SPA (React/Vue-like)
Phase 1: Recon – Mapping the Role Boundaries
I logged in as a normal user.
First rule:
Never trust what the UI hides.
I opened:
- DevTools → Network
- Application → Local Storage
- JWT decoder
Phase 2: JWT Inspection (Critical Insight)
JWT payload:
{
"user_id": 1042,
"role": "user",
"iat": 1712345678
}
🚩 Observation:
The backend knows roles exist.
Now the question becomes:
Are they enforced everywhere?
Phase 3: Frontend Lies (As Always)
In the UI:
- No admin links
- No moderation buttons
- Clean user dashboard
But the Network tab told a different story.
Phase 4: The Hidden Endpoint Discovery
While browsing normally, I noticed a 403 error in one request:
GET /api/admin/stats HTTP/1.1
Authorization: Bearer <JWT>
Interesting.
Why would a user ever call /api/admin/?
Answer:
The frontend bundles everything, then hides buttons.
Phase 5: Manual Access Attempt
I sent the same request manually via Burp Repeater.
GET /api/admin/stats HTTP/1.1
Host: example-app.com
Authorization: Bearer eyJhbGciOi...
Response:
{
"total_users": 48219,
"active_today": 9812,
"revenue": "₹1,24,000"
}
😶
No role check.
Phase 6: Escalating Horizontally → Vertically
Once read access works, try write access.
I enumerated endpoints using predictable naming:
/api/admin/users
/api/admin/users/delete
/api/admin/ban
Phase 7: The Real Break – Unauthorized Action
Tested carefully.
POST /api/admin/ban HTTP/1.1
Content-Type: application/json
Authorization: Bearer <JWT>
{
"user_id": 1088
}
Response:
{
"status": "user banned"
}
This was not my account.
This was not an admin token.
This was game over.
Why This Is Worse Than IDOR
Let’s compare.
| IDOR | Broken Access Control |
|---|---|
| Access other users’ data | Perform admin actions |
| Usually read-heavy | Often destructive |
| Limited scope | Full system takeover |
| Easy fix | Requires architecture changes |
Phase 8: Root Cause Analysis
❌ What the Developers Did
- Relied on frontend role checks
- Assumed “users won’t hit admin APIs”
- No centralized authorization middleware
✅ What Should Have Been Done
Authorization must be enforced on EVERY request.
Example (pseudo-code):
def require_admin(request):
if request.user.role != "admin":
return 403
Better:
- Policy-based access control (RBAC / ABAC)
- Middleware-level enforcement
- Deny by default
How I Systematically Hunt Broken Access Control
This is my exact mental checklist:
1️⃣ Identify roles
- JWT
- Cookies
- API responses
2️⃣ Enumerate endpoints
/admin/internal/manage/moderator
3️⃣ Ignore UI
- Direct API calls only
4️⃣ Test verbs
- GET → POST → PUT → DELETE
Tools Used
| Tool | Why |
|---|---|
| Browser DevTools | Endpoint discovery |
| JWT.io | Token inspection |
| Burp Suite | Manual authorization tests |
| Logic | Again, most important |
Real-World Impact
If abused maliciously:
- 🔥 User bans
- 🧨 Data deletion
- 🧑💻 Admin impersonation
- 💸 Financial manipulation
- ⚖️ Legal disaster
Severity:
Critical
Developer Fix Checklist (Bookmark This)
- ❌ Never trust frontend restrictions
- ✅ Enforce authorization server-side
- ✅ Use centralized middleware
- ✅ Log unauthorized attempts
- ✅ Test with least-privilege accounts
Final Thoughts: Why This Bug Keeps Existing
Because access control is:
- Boring to implement
- Easy to forget
- Hard to test
- Assumed to “just work”
Attackers love assumptions.
