Broken access control has been the top OWASP risk for years, and that is unlikely to change. The reason is simple — access control is the only security control that genuinely depends on the application's business model, and so it cannot be shipped as a library.
Pattern 1: UI-only enforcement
The front-end hides the "delete" button for non-admins, but the underlying API does not check the role. Any authenticated user can still call the endpoint.
How to test: log in as a low-privileged user, replay every privileged action from an admin session and observe responses.
Pattern 2: Insecure Direct Object Reference (IDOR)
An endpoint like GET /api/invoices/4815 returns the requested record without checking that the current user owns invoice 4815. Iterating IDs returns other tenants' data.
How to test: create two accounts in different tenants, swap any ID found in URLs or JSON responses, and check whether access is granted.
Pattern 3: Forced browsing
Hidden admin paths like /admin, /internal/users or /debug rely on obscurity. There is no actual check that the calling user has the admin role.
How to test: brute-force common admin paths and inspect responses for inconsistent authorization handling.
Defensive guidelines
- Always perform authorization on the server, even if the UI also hides actions.
- Centralize authorization logic — never spread role checks across dozens of controllers.
- Deny by default. Every new endpoint must be opted in to a permission.
- Log and alert on access-denied responses. Spikes are usually attacks in progress.
- Add automated tests for authorization with multiple personas — admin, member, guest.
If you only test one thing on your application this month, test authorization. It is the area where small mistakes have the largest blast radius.
Want a hands-on review of your stack?
Tell us about your application and we will scope a focused security engagement.