Every request to GET /api/orders/{id} needs two independent checks. Authentication asks "is this a real, logged-in user?" โ both API modes below pass this, since you're a legitimate customer with a valid token. Object-level authorization asks the harder question: "does this user own this specific order ID?" โ that's the check the vulnerable implementation skips.
// vulnerable
GET /api/orders/:id
if (!session.valid) return 401
return db.orders.find(id) // โ trusts the ID blindly
// secure
GET /api/orders/:id
if (!session.valid) return 401
const order = db.orders.find(id)
if (order.ownerId !== session.userId)
return 403 // โ object-level check
return order
- Target order ID โ the resource an attacker controls simply by editing a number in the URL or request body. No exploit tooling required.
- Vulnerable โ the server authenticates you, then returns whatever ID you asked for, no matter who it belongs to. Sweeping IDs harvests every other customer's private data.
- Secure โ the server additionally checks that the returned resource's owner matches your authenticated identity, rejecting every ID that isn't yours with 403, regardless of how valid your login is.
- Auto-sweep โ automates incrementing the ID parameter, the way a real IDOR enumeration attack walks sequential resource IDs.
This is OWASP API Security's #1 risk (Broken Object Level Authorization) precisely because authentication is necessary but not sufficient โ a perfectly legitimate login is often all an attacker needs.