Browse CTFs New CTF Sign in

IDOR (numeric)

web_auth_sessions Difficulty 1–5 30 min certifiable

Theory

Why This Matters

Numeric IDOR vulnerabilities have appeared in some of the highest-profile bug bounty disclosures of the past decade. In 2015, a researcher demonstrated that Facebook's graph API returned private photo albums when sequentially incrementing a numeric album_id parameter — a finding that earned a significant bounty and triggered a company-wide audit of object-level authorization. In 2021, the Peloton API exposed fitness and health data for any user when a numeric user_id was substituted in the /api/user/{id}/me endpoint, even without authentication. OWASP API1:2023 (Broken Object Level Authorization) exists primarily because numeric sequential identifiers are trivially enumerable and the authorization check is the single control standing between the identifier and the data. When that check is absent or inconsistent, mass data exposure follows.

Core Concept

Insecure Direct Object Reference (IDOR) in the numeric form occurs when an application uses sequential or otherwise predictable integers as object identifiers in URLs or request bodies and the server performs the database lookup without verifying that the requesting session is authorized to access the referenced object. The attacker's precondition is minimal: possess any valid session token and know (or enumerate) at least one valid object ID.

Sequential database primary keys (AUTO_INCREMENT in MySQL, SERIAL in PostgreSQL) are the most common source. Because IDs increment predictably, an attacker who obtains ID 1042 from their own account trivially infers that IDs 1041 and 1043 belong to other users. The enumeration attack simply loops across a range of integers and records every response that returns non-empty data.

Indirect numeric references add a layer of indirection: the application exposes a hash or opaque token in the UI, but the token maps server-side to a sequential integer. If that mapping can be reversed — for instance, if a Base64-decoded value reveals the underlying integer — the indirect reference provides no security benefit.

Blind IDOR describes the scenario where the server performs an action (e.g., deletes or modifies a record) without returning the object's contents in the response. The attacker detects the IDOR by observing a change in HTTP status code (200 vs. 404 for existence inference) or response timing rather than by reading the returned data.

Mass assignment leading to IDOR occurs when a framework automatically binds request parameters to model fields, allowing an attacker to set a foreign key (e.g., order.user_id) in the request body, thereby re-assigning an object to their own account — the inverse of classic IDOR but equally damaging.

Technical Deep-Dive

-- Attacker knows their own invoice ID is 5500
GET /api/invoices/5500 HTTP/1.1
Host: victim.com
Authorization: Bearer <attacker_token>

HTTP/1.1 200 OK
{"id":5500,"user_id":301,"total":199.00,"items":[...]}

-- Enumerate adjacent IDs
GET /api/invoices/5499 HTTP/1.1
Host: victim.com
Authorization: Bearer <attacker_token>

HTTP/1.1 200 OK    <-- IDOR confirmed
{"id":5499,"user_id":300,"total":849.50,"items":[...]}
# Burp Intruder equivalent in Python — enumerate invoices 5400-5600
import requests, json

TOKEN = "attacker_bearer_token"
HEADERS = {"Authorization": f"Bearer {TOKEN}"}
MY_USER_ID = 301
results = []

for iid in range(5400, 5601):
    r = requests.get(f"https://victim.com/api/invoices/{iid}", headers=HEADERS)
    if r.status_code == 200:
        data = r.json()
        if data.get("user_id") != MY_USER_ID:
            results.append({"id": iid, "owner": data["user_id"], "total": data["total"]})

print(json.dumps(results, indent=2))
# Output: list of invoices belonging to other users
-- Blind IDOR via DELETE — infer existence from 200 vs 404
DELETE /api/comments/8821 HTTP/1.1
Host: victim.com
Authorization: Bearer <attacker_token>

HTTP/1.1 200 OK      -- comment existed and was deleted (another user's comment)
{}

DELETE /api/comments/9999 HTTP/1.1
Host: victim.com
Authorization: Bearer <attacker_token>

HTTP/1.1 404 Not Found  -- does not exist

Security Assessment Methodology

  1. Identify your own object IDs — interact with the application normally as a low-privilege user and record every numeric identifier that appears in API responses, URLs, and request bodies.
  2. Map all object-scoped endpoints — search JS bundles and API specs for endpoint patterns containing {id}, {user_id}, {order_id}, etc.
  3. Two-account confirmation — create a second account (Account B), note its object IDs, and verify that Account A's token can access Account B's objects. This is the definitive proof of IDOR.
  4. Automate enumeration with Burp Intruder — set the numeric ID as the payload position, use a Numbers payload from the known-good value ± 100, and grep responses for data belonging to other users (look for user_id values differing from your own).
  5. Test POST/PATCH body parameters — use Burp Param Miner to discover hidden numeric parameters in request bodies; substitute other users' IDs.
  6. Test for indirect reference reversal — if IDs appear to be encoded (Base64, hex), decode them to check for underlying sequential integers.
  7. Verify mass assignment — on update endpoints, add a user_id or owner_id field to the request body and observe whether the server accepts and applies it.

Defensive Countermeasure — Replace sequential integer IDs with cryptographically random UUIDs (UUID v4) in all external-facing API responses to raise the cost of enumeration. More critically, enforce server-side ownership checks: every handler must query WHERE id = ? AND owner_id = ? (or equivalent), never WHERE id = ? alone. Implement this check in a shared middleware or repository layer to prevent per-endpoint omissions.

Common Assessment Errors

  • Only incrementing by 1 — IDs may skip ranges due to deletions, soft deletes, or multi-tenant partitioning; use a wider range (±500 or more) and accept gaps in the number line.
  • Concluding UUIDs are safe without testing — UUID v4 is random but may be leaked in emails, notifications, or other API responses; always check for UUID leakage before concluding that enumeration is impractical.
  • Missing POST body IDORs — automated scanners focus on URL parameters; manually review every JSON request body for integer fields that might reference another user's object.
  • Treating 403 as definitive — a 403 on GET does not mean PUT/PATCH/DELETE are also protected; some applications enforce read access but not write access on the same object.
  • Not testing blind operations — delete and status-update operations that return empty 200 bodies conceal IDOR; enumerate and compare response codes to detect existence without content.
  • Ignoring mass assignment — adding "user_id": <victim_id> to an update request body is a write-path IDOR that can silently re-attribute objects; test all update endpoints for extraneous field acceptance.

NICE Framework Alignment

Code Knowledge/Skill/Task Statement How This Card Develops It
K0007 Knowledge of authentication, authorization, and access control methods Explains object-level authorization as a required server-side check distinct from session authentication
K0065 Knowledge of policy-based and attribute-based access control Covers ownership-based access policy and the consequences of its absence for sequentially identified objects
S0001 Skill in conducting vulnerability scans and recognizing vulnerabilities in security systems Practises numeric enumeration with Burp Intruder, two-account testing, and blind IDOR detection techniques
T0028 Task: Identify systemic security issues based on vulnerability and configuration data Develops ability to recognize sequential IDOR as a systemic pattern affecting every object-scoped endpoint

Further Reading

  • OWASP API Security Top 10 — API1:2023 Broken Object Level Authorization — OWASP Foundation
  • Web Security Academy: Insecure Direct Object References — PortSwigger
  • Hacking APIs: Breaking Web Application Programming Interfaces — Corey Ball, No Starch Press (2022)
  • Real-World Bug Hunting — Peter Yaworski, No Starch Press (2019)

Challenge Lab

Reinforce your learning with a hands-on generated challenge based on this card's competency.