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
UUIDwithgen_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
- OWASP: Insecure Direct Object References
- CWE-639: Authorization Bypass Through User-Controlled Key
- PostgreSQL: UUID Type
Related Checks
- Supabase RLS Safety — AUTH-02, AUTH-03
- Server-Side Auth for Protected Routes — AUTH-04
- Multi-Tenancy Isolation — AUTH-19
Is your app safe? Run Free Scan →