Application Security
Intermediate 17 min read Application Security

IDOR and Broken Access Control

The most common silent killer: horizontal and vertical access-control gaps, the Insecure Direct Object Reference subset, and how to test authorization like a two-account puzzle.

IDORbroken access controlauthorizationhorizontal privilege escalationvertical escalationobject reference
Introduction

What is this?

Broken access control means a user can reach a resource they were never meant to reach: someone else's record (horizontal), an admin function (vertical), or a list they shouldn't enumerate.

Motivation

Why do you need it?

  • It is routinely the number-one-ranked web risk because the flaw lives in business logic, invisible to scanners.
  • The blast radius is huge: IDOR across an API commonly exposes every customer record with a single sequence number.
  • Learning to test as 'user A vs user B' is the single most transferable pentest skill.
Think about it

Mental model

Imagine

A shared filing room

Think of

Unlocked cabinets labeled by customer number

The labels are sequential, the handles are unlocked, and nobody checks who walks in.

Mechanics

How it works

  • The app trusts the user-supplied object ID (invoice/1234, uid=42) and authenticates the session but never authorizes the object.
  • Horizontal: user A reads user B's same-type object. Vertical: a normal user calls an admin endpoint directly.
  • Scanners know nothing about your business objects, so discovery requires two accounts and manual inference.
  • The fix is a middleware check on every object fetch: does THIS principal have rights over THIS resource?

A present-absent authorization path

Request
Authenticate
Authorize?
Allow/Deny
Log
Real world

In production

  • A SaaS added an object-access policy layer at the API gateway; invoice/1234 for user B now 403s before the handler runs.
  • A fintech's admin endpoints moved behind a separate middleware that checks 'is_admin' on every route, not just the menu.
  • A pentest found an IDOR in a PDF-export endpoint; the fix was a query scoping by the owner column instead of a raw id.
Guidelines

Best practices

  • Authorize every object access with an explicit owner check; never scope queries by id alone.
  • Use non-enumerable identifiers (UUIDs) AND enforce authorization — you need both layers.
  • Centralize the authorization check (policy/permission service) so every route hits the same gate.
  • Return the same 403/404 for both 'no such record' and 'no access' to stop enumeration signaling.
Watch out

Common mistakes

  • Protecting the list page but forgetting the detail/export/download endpoints that show each single record.
  • Relying on 'the UI hides the button' as authorization while the API remains unguarded.
  • Authorizing at the controller for one path and skipping the identical logic in a bulk or admin endpoint.
  • Assume-only: never running the two-account differential test that would have found the bug.
When things break

Debugging tips

  • The two-account test: log in as A, capture the request/response; as B, replay and diff the result.
  • Swap a sequence id for a UUID and check whether the handler still resolves it — predictors rarely work with UUIDs.
  • Watch HTTP status codes: a 200 where a 403 belongs is the entire report in one number.
Security

Security considerations

  • Differential testing must use accounts and data you own in a lab; crossing into other users' records is out of bounds.
  • If you find an access-control gap in a real product, report through the ownership line — never demonstrate on live records.
  • Treat the access-control audit as part of every release: it is the cheapest regression to skip and the most damaging to miss.
Interviews

Interview checkpoint

Practice

Hands-on lab

Find the IDOR with a Two-Account Differential
45 min · intermediate
In progress
Objectives
  • Create two local accounts in DVWA/Juice Shop.
  • Prove a horizontal IDOR using the differential method.
  • Patch the example handler to scope by owner and re-test.

Find the IDOR with a Two-Account Differential

45 min · intermediate

0/5 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/2
1

IDOR is a specific flavor of...

2

User A reads user B's invoice by changing /invoice/5 to /invoice/6. This is...

Go deeper

Official documentation