From ddd976eedbfb64d99e589ec9c3a5245400074b0a Mon Sep 17 00:00:00 2001 From: devendra-w Date: Mon, 18 May 2026 11:44:24 +0530 Subject: [PATCH 1/2] feat: enable RLS on all Supabase tables and document security model --- .../migrations/20260517000000_enable_rls.sql | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 supabase/migrations/20260517000000_enable_rls.sql diff --git a/supabase/migrations/20260517000000_enable_rls.sql b/supabase/migrations/20260517000000_enable_rls.sql new file mode 100644 index 0000000..533ddaa --- /dev/null +++ b/supabase/migrations/20260517000000_enable_rls.sql @@ -0,0 +1,64 @@ +-- Migration: Enable Row Level Security on all tables +-- Created: 2026-05-17 +-- Description: Enables RLS and adds policies so users can only access their own data. +-- supabaseAdmin (service role key) bypasses RLS automatically for server-side ops. + +-- ============================================================ +-- USERS TABLE +-- ============================================================ +alter table users enable row level security; + +-- Users can only read their own row +create policy "users_select_own" + on users for select + using (id = auth.uid()::text); + +-- Users can only update their own row +create policy "users_update_own" + on users for update + using (id = auth.uid()::text); + +-- ============================================================ +-- GOALS TABLE +-- ============================================================ +alter table goals enable row level security; + +-- Users can only read their own goals +create policy "goals_select_own" + on goals for select + using (user_id = auth.uid()::text); + +-- Users can only insert goals for themselves +create policy "goals_insert_own" + on goals for insert + with check (user_id = auth.uid()::text); + +-- Users can only update their own goals +create policy "goals_update_own" + on goals for update + using (user_id = auth.uid()::text); + +-- Users can only delete their own goals +create policy "goals_delete_own" + on goals for delete + using (user_id = auth.uid()::text); + +-- ============================================================ +-- METRIC_SNAPSHOTS TABLE +-- ============================================================ +alter table metric_snapshots enable row level security; + +-- Users can only read their own snapshots +create policy "metric_snapshots_select_own" + on metric_snapshots for select + using (user_id = auth.uid()::text); + +-- Users can only insert their own snapshots +create policy "metric_snapshots_insert_own" + on metric_snapshots for insert + with check (user_id = auth.uid()::text); + +-- Users can only delete their own snapshots +create policy "metric_snapshots_delete_own" + on metric_snapshots for delete + using (user_id = auth.uid()::text); \ No newline at end of file From 2f4e8ab6234ed0654b6029b9b875471d92e9fc33 Mon Sep 17 00:00:00 2001 From: devendra-w Date: Mon, 18 May 2026 12:06:50 +0530 Subject: [PATCH 2/2] docs: add RLS security model to SECURITY.md --- SECURITY.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/SECURITY.md b/SECURITY.md index 78cbedf..dc991cd 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -33,6 +33,38 @@ Out of scope: - Social engineering attacks - Rate limiting / denial of service on free-tier Vercel/Supabase +## Row Level Security (RLS) + +DevTrack uses Supabase with Row Level Security enabled on all tables to ensure users can only access their own data. + +### Protected Tables + +| Table | RLS Enabled | Policies | +|-------|-------------|----------| +| `users` | ✅ | SELECT, UPDATE own row only | +| `goals` | ✅ | SELECT, INSERT, UPDATE, DELETE own rows only | +| `metric_snapshots` | ✅ | SELECT, INSERT, DELETE own rows only | + +### How It Works + +- All RLS policies use `auth.uid()` to match against the `id` or `user_id` column +- Users can only read, write, or delete their **own** rows +- `supabaseAdmin` (service role key) bypasses RLS automatically for trusted server-side operations — it is **never** exposed to the client +- The anon key has no access to any table by default + +### Migration + +RLS policies are defined in: + ## Disclosure Policy Once a fix is released, we will publish a summary in the [GitHub Security Advisories](https://github.com/Priyanshu-byte-coder/devtrack/security/advisories) page. Credit will be given to the reporter unless they prefer to remain anonymous. + +To apply locally: +```bash +supabase db push +``` + +### Security Principle + +All client-facing queries use the anon key with RLS enforcement. Server-side API routes use `supabaseAdmin` only when elevated privileges are required (e.g. creating a user on first login).