August 19, 2026
BOLA vs IDOR: What Security Teams Need to Know About Object Access Control
Authorization vulnerabilities remain among the most critical issues discovered during security assessments of modern APIs and web…

By Mohamed Basil
7 min read
Authorization vulnerabilities remain among the most critical issues discovered during security assessments of modern APIs and web applications.
Two terms frequently used to describe access-control flaws are BOLA (Broken Object-Level Authorization) and IDOR (Insecure Direct Object References).
While security practitioners sometimes use these terms interchangeably, understanding their relationship, technical mechanics, and subtle differences is essential for accurate vulnerability reporting and effective remediation.
This article explains what BOLA and IDOR mean, how they appear in modern API architectures, why switching to UUIDs does not solve the underlying security problem, and how to implement robust server-side authorization controls.
BOLA vs IDOR: Where Did the Terminology Come From?
The term IDOR entered common cybersecurity terminology through the OWASP Top 10 in 2007.
It described vulnerabilities where applications used client-supplied references to access internal objects without properly verifying whether the requesting user was authorized to access them.
For example:
GET /download.php?file=report_101.pdfGET /download.php?file=report_101.pdfIf changing 101 to 102 allowed a user to download another user's document, the application contained an IDOR vulnerability.
As application architectures evolved toward REST APIs, GraphQL, and microservices, the same fundamental authorization problem became increasingly common in API endpoints.
The OWASP API Security Top 10 introduced the dedicated classification Broken Object-Level Authorization (BOLA) to describe this API-specific authorization failure.
The distinction can be summarized as:
- IDOR is a broad term for direct object-reference vulnerabilities across web applications and other systems.
- BOLA is the API-focused classification that emphasizes whether the backend properly verifies access to the requested object.
The underlying security principle is the same:
A user must not be able to access an object simply because they know or control its identifier.
What Is IDOR?
An Insecure Direct Object Reference (IDOR) occurs when an application exposes a reference to an internal object — such as a database ID, filename, account number, or document identifier — and uses that reference to retrieve the object without properly verifying the caller's authorization.
A traditional example might look like:
GET /download_statement.php?file=statement_1042.pdfGET /download_statement.php?file=statement_1042.pdfIf an unauthorized user can change the request to:
GET /download_statement.php?file=statement_1043.pdfGET /download_statement.php?file=statement_1043.pdfand retrieve another customer's statement, the application has an IDOR vulnerability.
The important factor is not the identifier itself.
The vulnerability exists because the application fails to enforce an authorization boundary around the referenced object.
What Is BOLA?
In modern API architectures, endpoints are commonly structured around object identifiers.
Examples include:
GET /api/v1/organizations/{org_id}/users
GET /api/v1/projects/{project_id}/documents/{doc_id}
PUT /api/v1/users/{user_id}/profileGET /api/v1/organizations/{org_id}/users
GET /api/v1/projects/{project_id}/documents/{doc_id}
PUT /api/v1/users/{user_id}/profileBOLA occurs when the API extracts an object identifier from the request, retrieves the corresponding record, but fails to verify whether the authenticated identity has permission to interact with that specific object.
For example:
GET /api/v1/projects/project_123/documents/doc_456
Authorization: Bearer <User_A_Token>GET /api/v1/projects/project_123/documents/doc_456
Authorization: Bearer <User_A_Token>The backend must determine whether User_A is actually authorized to access doc_456.
Simply possessing a valid authentication token does not automatically authorize access to every object within the application.
This distinction is critical:
Authentication answers "Who are you?" Authorization answers "What are you allowed to access?"
Horizontal vs. Vertical Privilege Escalation
Authorization flaws commonly appear in two structural forms.
1. Horizontal Privilege Escalation
Horizontal privilege escalation occurs when a user accesses resources belonging to another user with the same privilege level.
For example:
- User A is a standard customer.
- User B is also a standard customer.
- User A changes an object identifier in an API request.
- The API returns User B's billing information.
Both users have the same role, but User A has crossed the intended object ownership boundary.
This is a classic BOLA scenario.
2. Vertical Privilege Escalation
Vertical privilege escalation occurs when a lower-privileged user gains access to functionality or objects intended for a higher-privileged role.
For example:
- A standard user discovers an administrative endpoint.
- The user invokes an administrative API operation.
- The backend fails to enforce the required role.
- The standard user performs an administrator-only action.
Another example could involve manipulating an object such as:
{
"role": "superadmin"
}{
"role": "superadmin"
}during a profile update if the backend fails to restrict which attributes the user is allowed to modify.
The distinction is useful during security testing because object-level authorization and function-level authorization can fail independently.
The Identifier Myth: Why UUIDs Are Not an Authorization Control
One of the most common misconceptions in API security is:
"We use UUIDs, so BOLA isn't possible."
This is incorrect.
Replacing sequential integer identifiers such as:
101
102
103101
102
103with UUIDs such as:
f47ac10b-58cc-4372-a567-0e02b2c3d479f47ac10b-58cc-4372-a567-0e02b2c3d479makes identifiers significantly harder to enumerate.
However:
UUIDs do not enforce authorization.
Consider:
GET /api/v1/documents/f47ac10b-58cc-4372-a567-0e02b2c3d479
Authorization: Bearer <User_A_Token>GET /api/v1/documents/f47ac10b-58cc-4372-a567-0e02b2c3d479
Authorization: Bearer <User_A_Token>If the UUID belongs to User B and the backend returns the document without verifying User A's authorization, the application is still vulnerable to BOLA.
The identifier format is irrelevant to the authorization decision.
UUIDs can make automated enumeration more difficult, but the identifier may still be exposed through:
- Shared links
- API responses
- Client-side logs
- Referrer information
- Notifications
- Collaboration features
- Other application functionality
If an attacker obtains the UUID, a missing authorization check can still result in unauthorized access.
Security Rule
Obfuscation is not security.
The backend must evaluate authorization regardless of whether the object identifier is:
- An integer
- A UUID
- A random string
- A filename
- A database key
Realistic Code Example: Vulnerable Implementation
Consider a Node.js and Express endpoint:
// VULNERABLE: Retrieves document directly by ID
// without checking the authenticated tenant.
app.get('/api/v1/documents/:id', async (req, res) => {
const document = await DocumentRepository.findById(req.params.id);
if (!document) {
return res.status(404).json({ error: 'Document not found' });
}
// MISSING AUTHORIZATION CHECK
return res.json(document);
});// VULNERABLE: Retrieves document directly by ID
// without checking the authenticated tenant.
app.get('/api/v1/documents/:id', async (req, res) => {
const document = await DocumentRepository.findById(req.params.id);
if (!document) {
return res.status(404).json({ error: 'Document not found' });
}
// MISSING AUTHORIZATION CHECK
return res.json(document);
});The endpoint retrieves a document solely based on the supplied identifier.
There is no check confirming that the authenticated user or tenant owns the requested document.
If an attacker can obtain another user's document ID, the endpoint may return the object.
Secure Implementation: Enforcing the Tenant Boundary
A stronger implementation scopes the database query to the authenticated user's security context.
// SECURE: Enforces tenant ownership directly
// within the database query.
app.get('/api/v1/documents/:id', async (req, res) => {
const authenticatedTenantId = req.user.tenantId;
const document = await DocumentRepository.findOne({
_id: req.params.id,
tenantId: authenticatedTenantId
});
if (!document) {
// Avoid revealing whether the resource exists.
return res.status(404).json({
error: 'Document not found'
});
}
return res.json(document);
});// SECURE: Enforces tenant ownership directly
// within the database query.
app.get('/api/v1/documents/:id', async (req, res) => {
const authenticatedTenantId = req.user.tenantId;
const document = await DocumentRepository.findOne({
_id: req.params.id,
tenantId: authenticatedTenantId
});
if (!document) {
// Avoid revealing whether the resource exists.
return res.status(404).json({
error: 'Document not found'
});
}
return res.json(document);
});The important difference is the query:
{
_id: req.params.id,
tenantId: authenticatedTenantId
}{
_id: req.params.id,
tenantId: authenticatedTenantId
}The backend is no longer asking:
"Does this document exist?"
It is asking:
"Does this document exist and does it belong to the authenticated security context?"
That distinction is fundamental to preventing BOLA.
Returning 404 Not Found for unauthorized objects can also prevent attackers from confirming whether a particular object identifier exists.
How Security Engineers Test for BOLA
BOLA testing should be performed using authorized test accounts and clearly defined testing boundaries.
A practical testing methodology can use a multi-account matrix.
Step 1: Provision Test Accounts
Create at least two authorized test accounts in separate security contexts.
For example:
User A → Tenant A
User B → Tenant BUser A → Tenant A
User B → Tenant BThe accounts should have equivalent privileges when testing horizontal authorization.
Step 2: Record Valid Requests
Capture legitimate API requests generated by User A.
For example:
GET /api/v1/documents/doc_1001
Authorization: Bearer <User_A_Token>GET /api/v1/documents/doc_1001
Authorization: Bearer <User_A_Token>Record relevant:
- Object identifiers
- Authorization tokens
- Headers
- Parameters
- Request bodies
- HTTP methods
Step 3: Replay the Request Across Security Contexts
Using the authorized test environment, replay the request using User B's credentials.
For example:
GET /api/v1/documents/doc_1001
Authorization: Bearer <User_B_Token>GET /api/v1/documents/doc_1001
Authorization: Bearer <User_B_Token>The objective is to determine whether the API properly enforces the object ownership boundary.
Step 4: Analyze the Response
A response such as:
HTTP/1.1 200 OKHTTP/1.1 200 OKcontaining User A's protected data when authenticated as User B indicates a potential BOLA vulnerability.
A response such as:
HTTP/1.1 403 ForbiddenHTTP/1.1 403 Forbiddenor:
HTTP/1.1 404 Not FoundHTTP/1.1 404 Not Foundindicates that the access boundary is being enforced, assuming the application's intended authorization model supports that behavior.
Remediation: How to Prevent BOLA
Preventing BOLA requires server-side authorization controls rather than relying on identifier complexity or frontend restrictions.
1. Enforce Contextual Ownership Checks
Database queries should incorporate the authenticated security context.
For example:
SELECT *
FROM documents
WHERE id = :requested_id
AND tenant_id = :current_tenant_id;SELECT *
FROM documents
WHERE id = :requested_id
AND tenant_id = :current_tenant_id;The object should only be returned if both conditions are satisfied.
2. Centralize Authorization Policies
Authorization checks should not be scattered inconsistently throughout application code.
Use centralized middleware, authorization policies, or policy engines where appropriate.
Examples include:
- Open Policy Agent (OPA)
- CASL
- CanCan
- Framework-native authorization mechanisms
Centralization makes authorization behavior easier to audit, test, and maintain.
3. Avoid Leaking Unauthorized Object Existence
Where appropriate, return:
404 Not Found404 Not Foundinstead of:
403 Forbidden403 Forbiddenfor resources that the authenticated user should not be able to discover.
This can prevent unauthorized users from determining whether a particular object exists.
The exact response should still follow the application's security model and information-disclosure requirements.
4. Automate Authorization Boundary Tests
Authorization should be tested continuously.
Unit and integration tests should explicitly verify scenarios such as:
User A → User A Object → ALLOW
User A → User B Object → DENY
Tenant A → Tenant B Object → DENY
Standard User → Admin Object → DENY
Admin → Authorized Admin Object → ALLOWUser A → User A Object → ALLOW
User A → User B Object → DENY
Tenant A → Tenant B Object → DENY
Standard User → Admin Object → DENY
Admin → Authorized Admin Object → ALLOWAuthorization testing should be part of the development lifecycle rather than something performed only during an annual penetration test.
BOLA vs IDOR: The Key Takeaway
BOLA and IDOR describe closely related security problems, but the terminology reflects different contexts.
IDOR is the broader historical term for direct object-reference vulnerabilities.
BOLA is the modern API-focused classification used to describe broken authorization around individual objects.
Regardless of terminology, the security principle remains the same:
Knowing an object's identifier must never be sufficient to access it.
A secure API should always evaluate:
- Who is making the request?
- What resource are they requesting?
- What action are they attempting?
- Does their role permit that action?
- Does the resource belong to their authorized security context?
Changing numeric IDs to UUIDs can make enumeration harder.
It cannot replace authorization.
Conclusion
BOLA remains one of the most important authorization weaknesses in modern API architectures because it directly affects the isolation of application data.
The vulnerability is not fundamentally caused by predictable IDs.
It is caused by a missing authorization decision.
Effective mitigation requires:
- Server-side authorization
- Contextual ownership checks
- Proper tenant isolation
- Centralized access policies
- Automated authorization tests
- Careful handling of unauthorized resources
The most important rule for development and security teams is simple:
Never rely on an object's identifier to determine whether a user is authorized to access it.
Authorization must be enforced by the server on every request.
About KRAXXSEC
KRAXXSEC is a cybersecurity and security engineering practice focused on web application security, API security, vulnerability assessment, security testing, and practical remediation.
Learn more: https://kraxxsec.com
Request a Security Assessment: https://kraxxsec.com/security-assessment
Author
Mohamed Basil Founder & Principal Cybersecurity Consultant, KRAXXSEC
GitHub: https://github.com/Basilmellow
LinkedIn: https://www.linkedin.com/in/mohamed-basil-966a8225a/
Related Research
API Security Services: https://kraxxsec.com/services/api-security
What Is API Security Testing? A Practical Guide: https://kraxxsec.com/research/api-security-testing
Originally developed as part of the KRAXXSEC security research practice.