Any logged-in user can read and modify other customers' transactions
Surface: Database access control (Supabase Row-Level Security)
What we found
The transactions table had Row-Level Security enabled, but its SELECT and UPDATE policies only checked that the caller was authenticated, not that the row belonged to them. The UI filtered correctly, which hid the problem; calling the REST API directly returned every customer's rows.
Evidence — request made with test account B (redacted)
curl "https://[project].supabase.co/rest/v1/transactions?select=*" \
-H "apikey: [anon key]" \
-H "Authorization: Bearer [account B session]"
# 200 OK — 1,248 rows, including rows owned by account A
# and by 37 other organizationsBusiness impact
Every customer's financial data was readable, and editable, by any user with an account, including a free trial account.
Recommendation
Restrict both policies to rows owned by the caller's organization, and add a test that fails if another account can read a row.
create policy "org members read own transactions"
on transactions for select
using (org_id in (
select org_id from memberships where user_id = auth.uid()
));Retest
Fixed. The same request with account B now returns only account B's organization rows.