IDOR: The Bug That Refuses to Die (And How to Find It)

Manish Garg
Manish Garg Associate of (ISC)² · RingSafe
Apr 25, 2026
4 min read

Last updated: April 26, 2026

Insecure Direct Object Reference (IDOR) is the cybersecurity equivalent of “did you forget to lock the door?” It is one of the simplest vulnerabilities — change a number in a URL and access another user’s data. It is also one of the most common findings on web pentests in 2026, present on roughly half of Indian SaaS audits we run. This article covers why IDOR persists, how to find it systematically (manual + automated), and the architectural fix that closes the entire category.

Why IDOR keeps showing up

Three structural reasons:

  1. Authentication is checked; authorisation is not. The application verifies the user is logged in but doesn’t verify the user owns the resource being accessed. Common when developers conflate “authenticated” with “authorised.”
  2. Object IDs are predictable — sequential integers (user 1, user 2…). Even UUIDs leak via referrer logs, mobile app reverse engineering, or batch endpoints.
  3. Modern frameworks make authentication easy and authorisation manual. Every framework ships with auth middleware; few ship with object-level authorisation patterns. Developers add authorisation case-by-case and miss endpoints.

The taxonomy

IDOR comes in several flavours:

  • Sequential ID IDOR/api/users/123; change to 124 to read user 124.
  • UUID IDOR — UUIDs not guessable, but leaked through other channels (referrer headers, error messages, batch APIs that list all UUIDs).
  • Path-parameter IDOR/api/files/document.pdf; substitute another user’s filename.
  • Body parameter IDOR — POST body contains userId: 123; change to your target.
  • Header IDORX-User-ID: 123 header authenticated but spoofable.
  • Mass assignment IDOR — POST {"userId": 1, "amount": 100} where the userId field is accepted from input despite being implied by session.
  • Indirect IDOR — modify a related resource that has cascading access (change order ownership; now you can view its products).

How to find IDOR systematically

Manual workflow

  1. Create two test accounts (account A and account B).
  2. Log in as A; capture every request via Burp.
  3. For every request that contains an ID (numeric, UUID, slug, filename), substitute B’s equivalent ID.
  4. Replay; check if the response returns B’s data despite being authenticated as A.
  5. If yes — IDOR.

The Burp Pro extension Autorize automates this: configure two sessions; Autorize re-runs every request as both, flags requests where the responses are identical (suggesting authorisation is not enforced).

Variant tests

  • Forwarded headers — try X-Forwarded-User, X-User-ID with target user values.
  • JWT claim tampering — if JWT contains user ID, change it (combined with JWT attacks, very effective).
  • Mass assignment — POST request, add unexpected fields (userId, role, tenantId) and observe if the server accepts them.

Real-world examples (anonymised)

  • Indian healthtech app — patient profile endpoint /api/patients/<id>/medical-history returned any patient’s data given the ID. Tested with 50 sequential IDs; all worked. ~1.2M patient records reachable.
  • Fintech KYC service/api/kyc/<applicationId> returned PAN, Aadhaar, photograph for any application. Application IDs were sequential. We surfaced this as an immediate stop-the-rollout finding.
  • SaaS marketplace — invoice download by sequential invoice ID; no authorisation. Customers could read each other’s billing data.
  • Government portal (anonymised, 2024) — citizen-record API with mass-assignment IDOR; modifying a single field caused state-level data leakage for thousands of records.

The fix — architectural, not endpoint-by-endpoint

Patching individual endpoints leaves the next IDOR waiting to be discovered. The architectural fix:

  1. Object-level authorisation by default. Every database query should be scoped by the requesting user’s tenant / user ID. ORM-level: Order.where(user_id: current_user.id).find(params[:id]), not Order.find(params[:id]).
  2. Authorisation libraries. Pundit (Ruby), Cancan (Ruby), Casbin (Go/Python/Java/Node), CASL (JavaScript) — make authorisation declarative.
  3. Auth-by-convention frameworks. Some modern frameworks ship with row-level security as default. Use them where possible.
  4. Avoid exposing primary keys. Use UUIDs over sequential integers. Better, use scoped indirect references — /api/me/orders/<public-order-token> where the token is unguessable and only known to the authorised user.
  5. Mass assignment protection. Allow-list fields in mutation endpoints. Frameworks (Rails strong_params, Laravel fillable, etc.) enforce this when used correctly.
  6. Test in CI. Authentication + authorisation tests for every endpoint, automated. Coverage gaps are flagged on PR.

Detection in production

  • Anomalous access pattern detection — user accessing many distinct user IDs in a short window, then accessing none again. Often a manual or automated IDOR enumeration attempt.
  • 403 / 404 ratio increase from a single user — testing IDs and being denied for some, accessing others.
  • Application logs with row-level audit trails — every read of personal data logged with requesting user.

How to find your next IDOR

  • Burp Pro + Autorize extension. Run for an entire engagement against any application that has authenticated users.
  • Particularly test admin portals, file/document endpoints, exports, settings APIs, billing, audit-log access.
  • Mobile APIs are IDOR goldmines — backend developers often assume mobile clients are trusted.

Compliance angle

  • OWASP API Top 10 API1 (Broken Object Level Authorization) — IDOR is the canonical example.
  • DPDP §8(5) — IDOR allowing cross-tenant or cross-user access to personal data is a textbook reasonable-security failure.
  • RBI / SEBI — IDOR exposing customer data is a reportable cyber incident.

The takeaway

IDOR is the bug class where developer convenience and security collide. Adding authorisation to every endpoint is more work than skipping it, and the bug is invisible until tested. Run Autorize against your top customer-facing applications this quarter. Adopt an authorisation library or row-level pattern as a team-wide standard. The cost of one IDOR finding in personal-data territory is, conservatively, larger than the engineering investment to prevent the entire class.

Need a real pentest?

Get a VAPT scoping call

Senior practitioner-led VAPT — not a checklist run by juniors. CVSS-scored findings, free retest, attestation letter. India's SMBs and SaaS teams.

Book VAPT scoping call Replies in 4 working hrs · India-only · Senior consultants