ASAASA Standard
Not in Phase 1Production Foundation

UUIDs Not Sequential IDs

Admin Safety · ADM-07 · Priority: P1

Why It Matters

Sequential integer IDs (1, 2, 3, ...) are predictable. If an attacker sees their user ID is 42, they know user 41 and 43 exist — and can try to access their data by changing the ID in the URL or API request. This is called an Insecure Direct Object Reference (IDOR) attack.

UUIDs (a1b2c3d4-e5f6-...) are unpredictable. An attacker cannot guess other valid IDs, which adds a layer of defense even if authorization checks have gaps.

AI code generators frequently create tables with SERIAL or BIGINT primary keys because it's the simplest pattern. Supabase defaults to UUID for auth.users, but AI tools often create related tables with sequential IDs.

Priority: P1 — Enumeration attacks are trivial to automate. UUIDs are defense-in-depth.

Affected Stack: Supabase, PostgreSQL, any database


The Problem

-- ❌ What AI tools typically generate
CREATE TABLE invoices (
  id SERIAL PRIMARY KEY,  -- 1, 2, 3, 4...
  user_id UUID REFERENCES auth.users(id),
  amount INTEGER,
  status TEXT
);
GET /api/invoices/1    → My invoice
GET /api/invoices/2    → Someone else's invoice (if no auth check!)
GET /api/invoices/3    → Another user's invoice

Even with proper authorization, sequential IDs leak information — an attacker knows how many records exist and can estimate growth rate.


The Fix

Use UUIDs as primary keys for all user-facing tables.

-- ✅ UUIDs — unpredictable, no enumeration
CREATE TABLE invoices (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES auth.users(id),
  amount INTEGER,
  status TEXT
);
GET /api/invoices/a1b2c3d4-e5f6-7890-abcd-ef1234567890  → Valid
GET /api/invoices/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx    → Not found (can't guess)

Key rules:

  • Use UUID with gen_random_uuid() for all primary keys
  • Never expose sequential IDs in URLs, API responses, or client-side code
  • UUIDs are defense-in-depth — still implement proper RLS and auth checks
  • If you need sequential IDs for internal ordering, keep them in a separate non-exposed column

Note: UUIDs don't replace authorization. They complement it. Always combine UUIDs with server-side auth and RLS policies.

References


Related Checks


Is your app safe? Run Free Scan →