All vulnerabilities
HighA01:2021CWE-639Broken Access Control

Insecure Direct Object Reference (IDOR)

IDOR lets attackers access other users' data by manipulating object identifiers in requests — changing user IDs, document IDs, or UUIDs to reach unauthorized resources.

What Is IDOR?

Insecure Direct Object Reference (IDOR) occurs when an application uses user-controllable identifiers to access objects without verifying that the requesting user has permission to access that specific object. It is the most common access control vulnerability and appears constantly in AI-generated APIs.

How It Works

An API endpoint that returns order details:

// Vulnerable — no ownership check
app.get("/api/orders/:id", async (req, res) => {
  const order = await db.orders.findById(req.params.id)
  res.json(order)  // Returns any order, regardless of who's asking
})

A logged-in user knows their own order ID is 1042. They try:

GET /api/orders/1041
GET /api/orders/1000
GET /api/orders/1

Each request returns another user's order — name, address, payment details.

Sequential IDs make IDOR trivial. Even UUIDs don't prevent IDOR if no ownership check exists.

Real-World Impact

  • PII exposure — access other users' names, emails, addresses, phone numbers
  • Financial data — view payment methods, transaction history, invoices
  • Account takeover — endpoints like /api/users/:id/reset-password with IDOR
  • Data manipulation — modify or delete other users' records
  • Privilege escalation — access admin-only resources by guessing IDs

How to Fix

Always verify ownership server-side:

// Safe — checks that the order belongs to the authenticated user
app.get("/api/orders/:id", authenticate, async (req, res) => {
  const order = await db.orders.findOne({
    where: {
      id: req.params.id,
      userId: req.user.id,  // Must match the authenticated user
    }
  })
 
  if (!order) {
    return res.status(404).json({ error: "Not found" })
  }
 
  res.json(order)
})

Use non-sequential IDs (UUIDs) to reduce enumeration risk — but never as the only protection:

-- Use UUID primary keys
id UUID DEFAULT gen_random_uuid() PRIMARY KEY

Row-Level Security in Supabase/PostgreSQL:

-- Enforces ownership at the database level
CREATE POLICY "Users can only see their own orders"
  ON orders FOR SELECT
  USING (auth.uid() = user_id);

Centralize authorization — use middleware or policy objects rather than ad-hoc checks in each route.

What VibeWShield Detects

VibeWShield tests API endpoints for IDOR by attempting to access resources with incremented IDs, substituted UUIDs, and cross-user resource references. It flags endpoints that return data without apparent ownership validation.

#idor#authorization#access-control#api

Free security scan

Test your app for Insecure Direct Object Reference (IDOR)

VibeWShield automatically checks for Insecure Direct Object Reference (IDOR) and 40+ other vulnerabilities using 63 scanners — in under 3 minutes, no signup required.

Scan your app free