What BOLA actually is
Broken Object Level Authorisation (BOLA) — also known as Insecure Direct Object Reference (IDOR) in older OWASP terminology — is a class of authorisation flaw where an API endpoint grants access to a resource based on an identifier in the request, without verifying that the requesting user has permission to access that specific resource.
The mechanism is simple: User A has a valid token. User A knows (or can enumerate) the identifier for User B’s resource. The API endpoint checks that User A has a valid token but does not check that User A owns or is permitted to access the resource with that identifier. User A accesses User B’s data.
BOLA is the top OWASP API vulnerability because it is invisible to most automated scanners. A pattern-matching scanner looks for SQL injection patterns, cross-site scripting payloads, and known vulnerability signatures. BOLA does not produce an error or an unexpected response pattern — it produces a 200 OK with data that the requesting user should not have received. Only a scanner that understands the authorisation model of the specific application can detect it.
The case: paywall bypass in 31 minutes
All details below are anonymised. The customer was a B2B SaaS company (sector withheld) that had been running an annual pentest with a human firm for three years. No BOLA findings had been reported.
Scan initiated
AssurePort Web Pentest started with scope limited to production API surface. DCV verified, RoE signed.
Recon complete
47 API endpoints discovered. Tech stack: Node.js/Express, PostgreSQL, JWT auth. Paywall tier structure inferred from response schema differences between free and paid endpoints.
Auth analysis
JWT algorithm: RS256, no algorithm confusion. Sessions: stateless. Paywall enforcement: client-side tier check in frontend, separate API gate per endpoint. Gap identified: /api/reports/{id}/status endpoint missing tier check.
Exploit attempt
Free-tier token presented to /api/reports/{id}/status with a report ID belonging to a paid-tier account. Response: HTTP 200, full report content including premium fields. PoC recorded.
Validation
Second attempt with a different free-tier token and a different paid-tier report ID. Confirmed reproducible. Severity: HIGH (CVSS 3.1: 8.1).
Report delivered
Finding report available in dashboard with PoC curl command, CVSS score, and remediation recommendation. Customer notified by email.
The proof-of-concept
The PoC that arrived in the customer’s dashboard was a single curl command that any developer could reproduce in their terminal:
# Free-tier token (legitimately obtained)
TOKEN="eyJhbGciOiJSUzI1NiJ9.eyJ0aWVyIjoiZnJlZSIsInN1YiI6InVzZXJfMTIzIn0..."
# Report ID belonging to a paid-tier account (discovered via predictable ID enumeration)
REPORT_ID="rep_98765"
# BOLA exploit: free-tier token accessing paid-tier report
curl -s -H "Authorization: Bearer $TOKEN" \
https://api.[redacted].com/api/reports/$REPORT_ID/status | jq .
# Response: HTTP 200 with full paid-tier report content, including [redacted] premium fields
Why the annual pentest missed this: The human firm ran their annual test against a staging environment with synthetic data. The BOLA was only exploitable because the report IDs in production were sequential integers — a predictable pattern that the staging environment, which used UUIDs, did not reproduce. AI testing ran against the actual production surface.
The three-line fix
The remediation agent identified the specific Express route handler and generated the fix:
// Before: missing object-level authorisation check
router.get('/api/reports/:id/status', authenticate, async (req, res) => {
const report = await db.reports.findById(req.params.id);
return res.json(report);
});
// After: verify ownership before returning data
router.get('/api/reports/:id/status', authenticate, async (req, res) => {
const report = await db.reports.findById(req.params.id);
if (!report || report.userId !== req.user.id) { // line 1
return res.status(403).json({ error: 'Forbidden' }); // line 2
} // line 3
return res.json(report);
});
The customer deployed the fix within 24 hours of receiving the report. They also ran a secondary check across all 47 endpoints to identify any other instances of the same pattern — one additional endpoint was found and fixed in the same deploy.
The IDOR pattern across API designs
The paywall bypass described above is a specific variant of a broader IDOR/BOLA pattern. Common variants we encounter across web and API scans:
- Sequential integer IDs on resources that should be private (report IDs, invoice IDs, user profile IDs)
- Tenant isolation failures in multi-tenant SaaS — one tenant’s token accessing another tenant’s data
- Tier bypass via indirect endpoints — a premium endpoint is gated, but a utility endpoint that returns the same data is not
- File download IDOR — authenticated file download endpoints that check auth but not ownership
- Webhook IDOR — webhook payload endpoints that accept any authenticated request regardless of target resource ownership
Pattern-matching scanners miss all of these variants because they do not produce exploit signatures. They look like legitimate authenticated requests. Only a scanner that models the authorisation structure of the application — building a map of which users should have access to which resources — can systematically test for them. That is what the AI pentest pipeline does in the auth analysis phase.