Testing an API for authorization bugs with two accounts
Most serious API bugs are about who may do what. Use a simple matrix and two accounts to test it carefully and prove it cleanly.

APIs expose many operations, and the most valuable bugs are usually about authorization: whether the server checks that this user may do this action on this object. Because scanners cannot know what should be allowed, careful manual testing finds what they miss.
What you need
- Two ordinary test accounts you created (call them A and B) with the same role.
- If the app has roles, one account for each role (for example user and admin), only where the program allows creating them.
- A proxy (such as Burp) to record and replay requests.
- Written permission: the API is in scope.
Build a permission matrix
Make a table of actions against who should be allowed.
| Action | Anonymous | User A (own object) | User A (B's object) | Admin |
|---|---|---|---|---|
| View invoice | no | yes | no | yes |
| Edit profile | no | yes | no | yes |
| List all users | no | no | no | yes |
The cells marked no are your tests. For each one, the server must refuse.
The two main checks
1. Object-level authorization (BOLA / IDOR). Can A read or change B's object by using B's ID?
- As B, create an object and note its ID.
- As A, send the request for B's ID (view, update, delete).
- Expected: 403 or 404. A bug: 200 with B's data, or a successful change.
2. Function-level authorization. Can an ordinary user call an admin function? Look at the API paths you found (see reading JavaScript), try the admin ones with a normal user's token, and see whether the server refuses.
Other things to check
- Unauthenticated access: repeat a request with the token removed.
- Different HTTP methods on the same path (
GETallowed butDELETEunprotected). - Mass assignment: does the API accept extra fields such as
roleorisAdminin a request body and apply them? - Old API versions that might skip new checks.
- IDs in bodies and headers, not only in the URL.
- Indirect references: list endpoints that return other users' data, or exports and reports.
Use Repeater and compare
Record a request as user A. In Repeater, swap in B's identifier or token, send, and compare the response with the expected one. Change one thing at a time so you know what caused the result.
Safe proof
- Show that your own account A accessed your own account B's data, not a real customer's.
- If a test could expose real users (for example sequential IDs), do not enumerate. Prove with one example and report.
- Keep requests and responses (with sensitive values removed) for the report.
- Never modify or delete data that is not yours.
Reporting
Describe the rule that was broken ("an invoice should only be visible to its owner"), give the exact request, show the unexpected response, state the impact and suggest the fix (server-side ownership check). See our guide to writing a report.
Takeaway: use two accounts and a permission matrix, test object-level and function-level access one change at a time, and prove it with your own test data only.
Bug Bounty series, Part 2 (recon and tools): 5 of 5. Previous: Web archives and public sources: finding forgotten pages the right way.


