#2022·chatbot-ui

Security: Insecure Direct Object Reference(IDOR)

Author: JLGitHub66Created Apr 20, 2026Updated Apr 20, 2026

Summary

The chatbot-ui application contains two IDOR (Insecure Direct Object Reference) vulnerabilities that allow authenticated users to:

  1. Username Enumeration: Retrieve any user's username by providing their user ID
  2. API Key Exfiltration: Retrieve other users' custom model configurations including sensitive API keys

Both vulnerabilities exploit the use of Supabase SERVICE_ROLE_KEY which bypasses Row Level Security (RLS) policies, combined with insufficient authorization checks on user-controlled input.

Impact

Username Enumeration:

  • Attackers can enumerate all usernames in the system
  • Enables further attacks like social engineering or targeted phishing

API Key Exfiltration:

  • Attackers can steal other users' API keys for AI services
  • Results in financial loss (attacker uses victim's API quota)
  • Potential data breach if API keys provide access to sensitive AI services
  • Privacy violation (access to other users' model configurations)

Proof of Concept

Username Enumeration:

typescript
// POST /api/username/get
POST /api/username/get HTTP/1.1
Content-Type: application/json
Authorization: Bearer <attacker_token>

{"userId": "target_user_id"}

Response reveals the target user's username:

json
{"username": "victim_username"}

API Key Exfiltration:

typescript
// POST /api/chat/custom
POST /api/chat/custom HTTP/1.1
Content-Type: application/json
Authorization: Bearer <attacker_token>

{
  "chatSettings": {...},
  "messages": [...],
  "customModelId": "target_users_custom_model_id"
}

Response uses the victim's API key, attacker can analyze error messages to extract the key or use the key directly.

Note: This PoC is based on static analysis and has not been dynamically verified.

Affected Component

  1. Username Enumeration: app/api/username/get/route.ts
typescript
const supabaseAdmin = createClient<Database>(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.SUPABASE_SERVICE_ROLE_KEY!  // Bypasses RLS
)

// Directly queries any user by userId provided by attacker
const { data, error } = await supabaseAdmin
  .from("profiles")
  .select("username")
  .eq("user_id", userId)  // Attacker controls userId
  .single()
  1. API Key Exfiltration: app/api/chat/custom/route.ts
typescript
const { data: customModel, error } = await supabaseAdmin
  .from("models")
  .select("*")
  .eq("id", customModelId)  // Attacker controls customModelId
  .single()

// Attacker can access api_key field
const custom = new OpenAI({
  apiKey: customModel.api_key || "",
  baseURL: customModel.base_url
})

Root Cause

  1. Missing authorization: No check if the requesting user owns the resource
  2. Service role key usage: Using SUPABASE_SERVICE_ROLE_KEY bypasses all RLS
  3. User-controlled ID: Direct object references (userId, customModelId) are not validated
  4. Sensitive data exposure: API keys stored without proper access control

Suggested Fix

Please maintainer evaluate. Suggested mitigations:

  1. Add ownership validation:
typescript
// Username endpoint
const { data: profile } = await supabase
  .from("profiles")
  .select("username")
  .eq("user_id", userId)
  .eq("id", currentUser.id)  // Only allow access own profile
  .single()

// Custom model endpoint  
const { data: customModel } = await supabaseAdmin
  .from("models")
  .select("*")
  .eq("id", customModelId)
  .eq("user_id", currentUser.id)  // Only allow access own models
  .single()
  1. Use anon key instead of service role key:
typescript
// Use regular Supabase client with RLS
const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
  1. API key encryption: Encrypt API keys at rest and only decrypt when needed

  2. Remove sensitive fields from queries: Don't select api_key unless necessary