From da266d437f078a64508bb525b4f53b6db371b30d Mon Sep 17 00:00:00 2001 From: Maksim Soltan Date: Wed, 1 Apr 2026 07:53:12 -0700 Subject: [PATCH] fix: telemetry-ingest uses anon key not service role key The service role key bypasses Row Level Security entirely and grants unrestricted access to all Supabase tables and admin operations. Using it in a public-facing edge function called by all gstack users is a significant unnecessary privilege escalation. The anon key with INSERT-only RLS policies is the correct approach: - telemetry_events: anon can INSERT (migration 001/002) - installations: anon can INSERT (migration 001/002) - No SELECT, UPDATE, DELETE for anon - The service role key should never touch the public network path RLS INSERT policies are already in place (migration 001_telemetry.sql + 002_tighten_rls.sql). Switching to SUPABASE_ANON_KEY is safe. Closes #675 --- supabase/functions/telemetry-ingest/index.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/supabase/functions/telemetry-ingest/index.ts b/supabase/functions/telemetry-ingest/index.ts index 07d65d364..125f69f65 100644 --- a/supabase/functions/telemetry-ingest/index.ts +++ b/supabase/functions/telemetry-ingest/index.ts @@ -43,9 +43,15 @@ Deno.serve(async (req) => { return new Response(`Batch too large (max ${MAX_BATCH_SIZE})`, { status: 400 }); } + // Use the anon key, not the service role key. + // The service role key bypasses Row Level Security (RLS) and grants full + // unrestricted database access — wildly over-privileged for a public + // telemetry endpoint that only needs INSERT on two tables. + // The anon key + properly configured RLS INSERT policies is correct. + // See: https://supabase.com/docs/guides/database/postgres/row-level-security const supabase = createClient( Deno.env.get("SUPABASE_URL") ?? "", - Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "" + Deno.env.get("SUPABASE_ANON_KEY") ?? "" ); // Validate and transform events