📋 What Is It?
Insecure Authorization covers failures in the decision about what an already-identified user is allowed to do. The category exists because mobile apps repeatedly make or enforce that decision in the wrong place: inside the client, where the user controls everything, instead of on the server, where the attacker controls nothing.
A mobile app is not a trust boundary. It can be decompiled, hooked, and its local storage rewritten - and, most importantly, it can be ignored entirely while the attacker talks straight to the back end. Any permission check that lives only in the app is advisory. If the server does not re-derive the caller's identity and re-check their entitlements on every request, it is relying on the honesty of a component the attacker owns.
⚠️ Common Exploits
- Hidden UI as Control: the admin button is not rendered, the endpoint is unprotected
- Client-Supplied Role: server trusts
role/is_adminfrom the request - IDOR:
/api/accounts/{id}returns any id to any valid token - Unprotected Admin Routes: no role check because "only staff have the screen"
- Local Entitlements: premium/feature flags stored on device and edited
- Trusted Device Identifiers: access decided by a spoofable device id
- Stale Permissions: entitlements cached on device long after revocation
🔴 Attack Flow
↓
2. Decompile to find endpoints the UI never shows your role
↓
3. Call those endpoints directly with your own valid token
↓
4. Swap object ids and role fields; edit local entitlement flags
↓
5. IMPACT: Other users' data and privileged operations from a basic account!
❌ Vulnerable Code
✅ Secure Code
✓ Prevention Checklist
- Make every authorization decision on the server, on every request
- Derive identity only from the verified session or token
- Never accept role, tenant, entitlement, or user id from the client
- Check per-object ownership, not just "is authenticated"
- Protect every privileged endpoint, whether or not the UI exposes it
- Treat client-side UI gating as convenience only
- Keep permissions server-side; refresh them and honour revocation quickly
- Deny by default; require an explicit grant to proceed
- Return 404 rather than 403 for objects the caller may not see
- Log authorization denials and alert on enumeration patterns
- Test the API without the app - it is how an attacker will
🔍 Detection & Tools
Testing:
Server Policy:
How to Test:
- Replay an admin request with a normal user's token
- Change object ids in requests and look for successful responses
- Add
role/is_adminfields and see whether the server believes them - Edit local entitlement flags and check whether the server re-validates
- Revoke a permission server-side and confirm the app loses access promptly
🌍 Real-World
These are documented incident classes - recurring patterns rather than single CVEs.
- Account enumeration through the mobile API: an endpoint returning any account id to any authenticated caller exposes balances and statements across the customer base.
- Hidden admin functions called directly: staff-only operations reachable by any user because the check lived in the app.
- Local premium flags: paid features unlocked by editing a preference file on a rooted device.
- Client-declared roles: back ends that accept a role field from the request and act on it.
- Stale entitlements: access that persists on device long after it was revoked server-side.
📌 Quick Tips
- DO NOT let the app decide what the user may do
- DO NOT trust ids, roles, or flags from the client
- DO re-check identity and entitlement per request
- DO verify per-object ownership
- DO deny by default and log denials
📜 Compliance
Related Standards:
- OWASP Mobile Top 10 2016 - M6
- Merged into M3:2024 Insecure Authentication/Authorization
- OWASP MASVS AUTH-2, AUTH-3
- CWE-285 Improper Authorization
- CWE-639 Authorization Bypass Through User-Controlled Key
- CWE-862 Missing Authorization