Skip to content

[Security] Bulk send does not verify phone number ownership (missing user_id filter) #42

@eltociear

Description

@eltociear

Summary

src/app/api/messages/bulk-send/route.ts fetches the phone number without filtering by user_id. An authenticated user can send bulk SMS from any phone number in the system, not just their own.

Location

// src/app/api/messages/bulk-send/route.ts
const { data: phoneNumber, error: phoneError } = await supabase
  .from("phone_numbers")
  .select("*")
  .eq("id", phoneNumberId)
  .single();  // No .eq("user_id", user.id) filter!

Compare with campaigns route which correctly verifies ownership:

// src/app/api/campaigns/route.ts (correct)
const { data: phoneNumber } = await supabase
  .from("phone_numbers")
  .select("id")
  .eq("id", phone_number_id)
  .eq("user_id", user.id)  // Ownership verified
  .single();

Impact

  • Any authenticated user can send bulk SMS from another user's phone number
  • The messages would be billed to the phone number owner's provider account
  • Could be used for impersonation or phishing
  • Note: single send (/api/messages/send/route.ts) has the same issue — no user_id filter on phone_numbers select

Suggested Fix

Add user_id filter:

const { data: phoneNumber, error: phoneError } = await supabase
  .from("phone_numbers")
  .select("*")
  .eq("id", phoneNumberId)
  .eq("user_id", user.id)  // Add ownership check
  .single();

Severity

High — Cross-user resource access, potential impersonation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions