Authorization testing: roles, permissions, and the assumptions that leak
Authentication asks "who are you?". Authorization asks "are you allowed?". Most access-control bugs live in the second question — here's how QA tests it.
part ofSecurity testing for QATeams pour effort into authentication — login, MFA, password rules — and then ship authorization as an afterthought: a few if (user.isAdmin) checks scattered through the code. That asymmetry is why access-control bugs are so common. Authentication is a single front door everyone notices; authorization is a thousand interior doors, and it only takes one left unlocked. This builds on IDOR (which is authorization failing on a specific object) and widens it to roles and permissions across the whole app.
Build the access matrix first
You can't test authorization without knowing what should be allowed. Before testing, sketch a small grid: roles down one side (viewer, editor, admin, billing-owner…), sensitive actions across the top (view reports, edit price, delete user, export data, change billing…). Each cell is allow or deny. That matrix is your oracle — every test is "log in as this role, attempt this action, confirm the matrix." Most teams have never written it down, and the act of filling it in surfaces contradictions before you run a single test.
Test the denies, not just the allows
The happy-path trap again: it's natural to confirm an admin can delete a user. The bug is whether a viewer can't. So for every deny cell in the matrix, actively attempt the action as the wrong role and confirm it's blocked server-side. Authorization testing is mostly negative testing — proving the locked doors are actually locked.
The UI is not access control
The single most common authorization bug: the frontend hides a button the user isn't allowed to use, and the backend never checks. Hidden ≠ forbidden. To test it, bypass the UI:
- Unhide the disabled/hidden control in dev tools and click it.
- Call the endpoint directly with a lower-privilege user's session.
- Replay an admin's captured request while authenticated as a regular user.
If the action succeeds because only the UI enforced the rule, that's a missing server-side check — a real, high-severity defect.
Privilege escalation: horizontal and vertical
- Vertical escalation: a lower role performing a higher role's action (a regular user hitting
/admin/users/5/delete). Walk every privileged action against every lower role. - Horizontal escalation: acting as a peer you shouldn't — editing another editor's document, viewing another billing-owner's invoices. This is IDOR wearing a role hat: same privilege level, wrong owner.
- Function-level holes: an endpoint that checks the role on the "list" view but forgets it on "export" or "bulk-edit". Test each function, not just the entry point.
The assumptions that leak
Authorization bugs cluster around unstated assumptions:
- State transitions: can you act on an object in a state that should forbid it — approve your own request, edit a locked record, refund an already-refunded order?
- Stale permissions: demote a user mid-session — does their existing session lose access immediately, or keep the old powers until logout?
- Indirect access: blocked from a record directly, but can you reach it through a related object, a search result, an export, or an API the UI doesn't use?
- Defaults: a brand-new resource or a newly added team member — does it default to least privilege, or accidentally inherit broad access?
Where this fits
This is the senior end of QA-safe security testing — still no exploit tooling, just systematic negative testing against a written access matrix. It pairs with IDOR explained for QA and the broader auth bugs pass. The security testing checklist has the structured version, and common bugs → auth & permissions catalogues the defect classes.
Authorization pass
- Write the role × action access matrix first — it's your oracle
- For every deny cell, attempt the action as the wrong role and confirm a server-side block
- Bypass the UI (unhide controls, call endpoints directly) — hidden is not forbidden
- Test vertical (lower role → higher action) and horizontal (peer's data) escalation
- Check each function of an endpoint (list/export/bulk), not just the entry view
- Probe state transitions, stale permissions after demotion, indirect access, and defaults
// RELATED QA.CODES RESOURCES
Checklist
Common Bug
// related
IDOR explained for QA engineers
The most common serious web vulnerability is also the easiest for QA to catch: the app serves a record by ID without checking it is yours. Two accounts and a changed number find it.
Prompt injection testing for QA engineers
LLMs can't reliably separate instructions from data, so user input can hijack the model. Direct and indirect injection, what to check for, and how to report it QA-safe.