Back to Cheat Sheets

๐Ÿ” Broken Object Level Authorization (BOLA)

OWASP API Security Top 10 - API01

CRITICAL RISK

๐Ÿ“‹ What Is It?

Broken Object Level Authorization (BOLA), also known as Insecure Direct Object Reference (IDOR), occurs when an API endpoint receives an object identifier and performs actions on that object without properly validating whether the requesting user has permission to access it. This is the #1 API security vulnerability.

API01 OWASP Rank
95% APIs Affected
<30min Time to Exploit

โš ๏ธ Common Exploits

  • Parameter Tampering: Modify user_id, order_id, or document_id in API requests
  • ID Enumeration: Iterate through sequential IDs to access all objects
  • URL Manipulation: Change resource identifiers in API endpoints
  • Body Manipulation: Modify object IDs in JSON request bodies
  • Batch Operations: Include unauthorized object IDs in bulk requests

๐Ÿ”ด Attack Flow

1. Attacker authenticates as regular user
โ†“
2. Observes API call: GET /api/orders/1234
โ†“
3. Changes ID: GET /api/orders/1235
โ†“
4. API doesn't verify ownership
โ†“
5. BREACH: Access to other user's order!

โŒ Vulnerable Code

// Bad: No ownership check! GET /api/orders/5827 Authorization: Bearer <token> // Backend code (Python Flask) @app.route('/api/orders/<order_id>') @login_required def get_order(order_id): # VULNERABLE: No ownership verification! order = Order.query.get(order_id) return jsonify(order) // Bad: Trusting client-provided object IDs POST /api/documents/share { "document_id": 9812, "share_with": "attacker@example.com" }

โœ… Secure Code

// Good: Verify ownership before access @app.route('/api/orders/<order_id>') @login_required def get_order(order_id): order = Order.query.get_or_404(order_id) # Verify user owns this order if order.user_id != current_user.id and not current_user.is_admin: abort(403) # Forbidden return jsonify(order) // Good: Filter by ownership in query @app.route('/api/orders') @login_required def get_user_orders(): # Only return user's own orders orders = Order.query.filter_by(user_id=current_user.id).all() return jsonify(orders) // Good: Use UUIDs + ownership checks def verify_ownership(resource, user): if resource.owner_id != user.id: raise PermissionError("Access denied")

โœ“ Prevention Checklist

  • Verify object ownership on every API request
  • Use user context from authentication token, never request
  • Implement database queries with ownership filters
  • Use random UUIDs instead of sequential IDs
  • Implement centralized authorization logic
  • Test with different user contexts
  • Log authorization failures for monitoring
  • Never trust client-provided object IDs
  • Use framework authorization libraries
  • Conduct regular security testing

๐Ÿ” Detection & Tools

Testing Tools:

Burp Suite OWASP ZAP Postman curl Insomnia APIFuzzer

Prevention Libraries:

Pundit (Ruby) CanCanCan (Ruby) Casbin Spring Security Django Guardian

How to Test:

  • Create two test accounts (User A and User B)
  • Capture API requests as User A
  • Replay requests as User B with User A's object IDs
  • Iterate through ID ranges to test enumeration
  • Test all HTTP methods (GET, POST, PUT, DELETE, PATCH)

๐ŸŒ Real-World Breaches

  • T-Mobile (2021): 40M+ customer records exposed via BOLA in customer API
  • Peloton (2021): API allowed access to any user's profile, workout data, and location
  • Parler (2021): 70TB of data scraped via sequential post ID enumeration
  • USPS (2018): 60M user accounts accessible by changing account parameter
  • Bumble (2019): User data accessible by iterating through user IDs

๐Ÿ“Œ Quick Tips

  • DO NOT trust any client-provided object IDs
  • DO NOT rely on UUIDs alone for security
  • DO NOT skip authorization checks for internal APIs
  • DO verify ownership on every request
  • DO use WHERE user_id = ? in database queries
  • DO log and monitor authorization failures

๐Ÿ“œ Compliance

Related Standards:

  • PCI-DSS Requirement 6.5.8
  • GDPR Art. 32 - Security of Processing
  • HIPAA ยง164.312 - Access Control
  • SOC 2 CC6.1, CC6.3
  • ISO 27001 A.9.4.1
  • NIST 800-53 AC-3