No. Random UUIDs make record IDs harder to guess, which OWASP recommends, but they do not fix broken object level authorization. If the server never checks that the caller may access that record, anyone who obtains a valid ID can read it. The ownership check is the control.
Definitions
IDOR (insecure direct object reference) and BOLA (broken object level authorization, API1:2023) describe the same flaw: the server trusts an ID from the client without confirming the caller is allowed to use it. OWASP notes the ID can be an integer, a UUID or a string, and can appear in the path, query string, headers or body.
What OWASP says
OWASP's prevention list for API1 has two separate points. First, check on every function that uses client input to reach a record whether the logged in user may perform that action on it. Second, prefer random and unpredictable values as GUIDs for record IDs. The second is a hardening step. The first is the fix. OWASP also says that comparing the session user ID to the ID parameter covers only a small subset of cases.
Why random IDs are not enough
| Situation | What happens |
|---|---|
| Sequential integer IDs, no check | Attacker counts up and reads everything |
| Random UUIDs, no check | Attacker needs one valid ID, then reads that record |
| Random UUIDs, with check | Valid ID from another user is refused |
IDs leak more often than teams expect:
- list endpoints that return other people's IDs
- IDs in shared links, emails and screenshots
- IDs in logs, analytics and error messages
- IDs known to former employees, partners or other tenants
Once an ID is known, only the authorization check stops access.
A quick worked example
User A creates an invoice and gets back a random ID. User A pastes the link into a support chat, and the ID lands in the chat history and a screenshot. Now a support contractor, or anyone who later sees that transcript, holds a valid ID. If the invoice endpoint checks only that the token is valid, that person can fetch the invoice. If it checks that the caller owns the invoice, or belongs to a role allowed to see it, the request fails. The ID format was never the deciding factor.
What to do
- Enforce ownership or role policy in one shared layer that every handler calls.
- Deny by default, as OWASP advises for function level checks.
- Use random identifiers for new records, from a cryptographically secure generator, as defence in depth.
- Write tests with two users: user A creates a record, user B requests it, expect a refusal.
- Run those tests in CI and block merges that fail, as OWASP recommends.
See how to test for BOLA with two accounts for the steps.
Quick check
Should I switch from integer IDs to UUIDs?
It is a sensible hardening step for new records, but do not treat it as the fix. Add the authorization check first.
Which status code should a refused request return?
403 states the caller is not permitted. Some teams return 404 to avoid confirming a record exists. Pick one, apply it consistently, and test it.
Safeguard provides policies and gates for enforcing checks in pull requests, and a free scan at gold.safeguard.sh/scan.
Sources
- OWASP API1:2023 Broken Object Level Authorization
- OWASP API5:2023 Broken Function Level Authorization
- OWASP REST Security Cheat Sheet
Last reviewed: 19 October 2026.