To review an authorization change, confirm that access is denied by default, that every request checks permission for the specific object being touched, and that a test proves a second user is refused. Logging in is not authorization. Most access control bugs hide in the endpoint nobody thought to check.
What the standards ask for
The OWASP Authorization Cheat Sheet lists a few principles that translate directly into review questions. Deny by default. Enforce least privilege. Validate permissions on every request, because an attacker needs only one missed check. Check access to the specific object, since access to one record of a type does not imply access to the others.
The OWASP API Security Top 10 puts the object level version of this first, as Broken Object Level Authorization. Its description is plain: an endpoint takes an object ID from the client and acts on it without checking that the signed in user may touch that object.
A reviewer's checklist
| Question | What a good answer looks like |
|---|---|
| What happens when no rule matches? | The request is refused, not allowed |
| Where does the check run? | In shared middleware or a policy layer, not copied into each handler |
| Does it check the object, or only the role? | The query or policy includes the owner or tenant |
| Which IDs come from the client? | Each one is checked against the caller before use |
| Is there a test with a second user? | One test fails if the check is removed |
Steps to follow in the diff
- Find every new route, handler or query in the pull request. List the object IDs each one accepts from the client.
- For each ID, find the line that ties the object to the caller. If you cannot find it, ask for it.
- Look at the default. A new route registered outside the protected router group is the common mistake.
- Check the write paths as hard as the read paths. Update and delete often get weaker checks than get.
- Read the tests. A test that logs in as the owner proves nothing about a stranger.
Patterns that deserve a second look
A comparison of the session user ID with the requested ID covers only a small subset of cases, as the OWASP API page points out. Shared resources, admin impersonation, team membership and soft deleted records all need their own rule.
Random IDs help but are not a control. OWASP recommends unpredictable IDs such as GUIDs as a preference, while the actual defense is the check on every access. Obscuring an identifier without checking it only slows a guesser down.
Role checks alone age badly. The cheat sheet notes that role based access handles object level and multi factor decisions poorly and can suffer from role explosion, and it recommends attribute and relationship based approaches for application development. In review terms: if the diff adds a fourth special role to patch one case, ask whether the rule should be about the relationship instead.
Try it yourself
Open the demo and run the API scan, then look at which findings relate to access to objects rather than to input handling.
Click through it at your own pace, or open it full screen.
Where Safeguard fits
Safeguard pull request policies and gates can block merges on dependency findings, and its free scan at gold.safeguard.sh/scan covers dependencies and SBOM. Authorization logic still needs a human reader and a good test.
Quick check
Is checking that the user is logged in enough?
No. Authentication says who the caller is. Authorization says what that caller may do to this specific object. Both must be checked on each request.
Do random IDs replace the check?
No. Unpredictable IDs make guessing harder, but the check on every access is the defense.
Sources
- OWASP Authorization Cheat Sheet
- OWASP API Security Top 10 2023, API1 Broken Object Level Authorization
Last reviewed: 19 October 2026.