Permission and Authorization Bugs

User Can Access Another User's Object

When an application looks up a resource by ID without verifying the requesting user owns or is permitted to access that specific record, any authenticated user can read, modify, or delete another user's data by supplying the other user's resource ID. This is an Insecure Direct Object Reference (IDOR) vulnerability.

CriticalIntermediateSecurity testingAPI testingManual testing

// UNDERSTAND

// Symptoms

  • Changing a numeric or UUID resource ID in the URL returns another user's data
  • A GET /api/orders/456 request by User B returns User A's full order details
  • No 403 Forbidden or 404 Not Found is returned when the record belongs to a different user
  • Personally identifiable information from a different account appears in the response
  • A PATCH or DELETE request targeting another user's resource ID executes successfully

// Root Cause

  • The backend queries the record by ID alone without a user ownership check — e.g. SELECT * FROM orders WHERE id = :id instead of WHERE id = :id AND user_id = :current_user
  • Route-level authentication (is the user logged in?) is enforced, but object-level authorization (does this user own this specific record?) is not
  • Sequential IDs lower the effort to enumerate targets — this increases blast radius but is not the root cause. UUIDs make IDOR harder to exploit but do not fix the missing authorization check

// Where It Appears

  • Order and purchase history endpoints: /api/orders/{id}
  • User profile and account detail pages: /api/users/{id}/profile
  • Document and file management systems
  • Support ticket systems where ticket IDs are sequential
  • Admin APIs where resource IDs are visible in frontend network requests

// REPRODUCE & TEST

// How to Reproduce

  1. 01Log in as User A and create a resource (e.g. submit an order); note the resource ID from the API response (e.g. orderId: 456)
  2. 02Log out of User A's session
  3. 03Log in as User B (a different test account)
  4. 04Send a GET request to /api/orders/456 using User B's authentication token
  5. 05Observe the response — it should be 403 Forbidden or 404 Not Found, not User A's order data

// Test Data Needed

  • Two distinct user accounts on the same application (User A and User B)
  • A resource created by User A with a known ID
  • A way to send API requests with a specific bearer token (browser DevTools, Postman, or curl)

// Manual Testing Ideas

  • Create a resource as User A, log out, log in as User B, and navigate directly to User A's resource URL
  • While browsing as User B, increment or decrement the ID in the URL and observe whether data loads
  • Test write-access IDOR: send PATCH and DELETE requests targeting User A's resource ID using User B's session
  • Verify that the error response on a denied request does not leak any of User A's data in the body
  • Test access across role boundaries: standard user trying to access admin-created records
  • Check nested routes for the same gap: /api/users/{userId}/documents/{docId}

// API Testing Ideas

  • Authenticate as User A; create a resource and capture its ID from the response body
  • Authenticate as User B; capture User B's bearer token from any authenticated request
  • Send GET /api/orders/{User A's resource ID} using User B's token
  • Assert the response is 403 Forbidden or 404 Not Found — not 200 with User A's data
  • Repeat with PATCH and DELETE methods targeting the same resource ID
  • Confirm the error response body contains no data from User A's record

// Automation Idea

Automate a two-user flow: authenticate as User A, create a resource and capture its ID from the response, then authenticate as User B and send GET /api/orders/{id} with User B's token. Assert HTTP 403 or 404. Extend to PATCH and DELETE with a mutation payload to verify write-access IDOR is also rejected.

// Expected Result

Requests by User B for resources owned by User A return 403 Forbidden or 404 Not Found, with no data from User A's record in the response body.

// Actual Result (Example)

A GET request to /api/orders/456 with User B's bearer token returns 200 OK containing User A's full order details including item list, billing address, and payment method.

// REPORT IT

Example Bug Report

Title
Authenticated user can read another user's order details by changing the order ID
Severity
Critical
Environment
Staging environment Chrome 124 Two standard user accounts (User A and User B)
Steps to Reproduce
  1. 01Log in as User A and submit an order; note the order ID from the API response (e.g. 456)
  2. 02Log out of User A's session
  3. 03Log in as User B
  4. 04Send GET /api/orders/456 using User B's bearer token
  5. 05Observe the response body
Expected Result
The API returns 403 Forbidden or 404 Not Found.
Actual Result
The API returns 200 OK with User A's full order details including billing address, items, and payment method.
Impact
Any authenticated user can enumerate resource IDs to read, modify, or delete other users' private data, exposing sensitive personal and financial information.

// RELATED