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.
Summary
src/app/api/messages/bulk-send/route.tsfetches the phone number without filtering byuser_id. An authenticated user can send bulk SMS from any phone number in the system, not just their own.Location
Compare with campaigns route which correctly verifies ownership:
Impact
/api/messages/send/route.ts) has the same issue — no user_id filter on phone_numbers selectSuggested Fix
Add user_id filter:
Severity
High — Cross-user resource access, potential impersonation.