From aee512b8a1cda1bad435868ed5c6cd7eccf9bb23 Mon Sep 17 00:00:00 2001 From: pac7 <47831526-pac7@users.noreply.replit.com> Date: Wed, 8 Oct 2025 12:56:58 +0000 Subject: [PATCH] Improve security by auditing service role key usage in edge functions Audit and document the usage of service role keys in multiple Supabase edge functions (cancel-email-change, process-selective-approval, seed-test-data) to ensure secure and scoped access. Replit-Commit-Author: Agent Replit-Commit-Session-Id: fe5b902e-beda-40fc-bf87-a3c4ab300e3a Replit-Commit-Checkpoint-Type: intermediate_checkpoint --- .replit | 4 ++++ supabase/functions/cancel-email-change/index.ts | 10 ++++++++-- supabase/functions/process-selective-approval/index.ts | 5 +++++ supabase/functions/seed-test-data/index.ts | 7 +++++++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/.replit b/.replit index fc81a45d..3c2d687d 100644 --- a/.replit +++ b/.replit @@ -33,3 +33,7 @@ outputType = "webview" [[ports]] localPort = 5000 externalPort = 80 + +[[ports]] +localPort = 44859 +externalPort = 3000 diff --git a/supabase/functions/cancel-email-change/index.ts b/supabase/functions/cancel-email-change/index.ts index a97f6959..ec3feda4 100644 --- a/supabase/functions/cancel-email-change/index.ts +++ b/supabase/functions/cancel-email-change/index.ts @@ -22,8 +22,14 @@ Deno.serve(async (req) => { // Extract the JWT token from the Authorization header const token = authHeader.replace('Bearer ', ''); - // Create admin client with service role key (no user token in global headers) - // This ensures all DB operations run with full admin privileges + // SECURITY: Service Role Key Usage + // --------------------------------- + // This function uses the service role key to bypass RLS and access auth.users table. + // This is required because: + // 1. The cancel_user_email_change() database function has SECURITY DEFINER privileges + // 2. It needs to modify auth.users table which is not accessible with regular user tokens + // 3. User authentication is still verified via JWT token (passed to getUser()) + // Scope: Limited to cancelling the authenticated user's own email change const supabaseUrl = Deno.env.get('SUPABASE_URL'); const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY'); diff --git a/supabase/functions/process-selective-approval/index.ts b/supabase/functions/process-selective-approval/index.ts index ca97e9fb..01a7258b 100644 --- a/supabase/functions/process-selective-approval/index.ts +++ b/supabase/functions/process-selective-approval/index.ts @@ -73,6 +73,11 @@ serve(async (req) => { { status: 401, headers: { ...corsHeaders, 'Content-Type': 'application/json' } } ); } + + // SECURITY NOTE: Service role key used later in this function + // Reason: Need to bypass RLS to write approved changes to entity tables + // (parks, rides, companies, ride_models) which have RLS policies + // Security measures: User auth verified above, moderator role checked via RPC const authenticatedUserId = user.id; diff --git a/supabase/functions/seed-test-data/index.ts b/supabase/functions/seed-test-data/index.ts index d6ca448e..022bc6ee 100644 --- a/supabase/functions/seed-test-data/index.ts +++ b/supabase/functions/seed-test-data/index.ts @@ -35,6 +35,13 @@ Deno.serve(async (req) => { } try { + // SECURITY: Service Role Key Usage + // --------------------------------- + // This function uses the service role key to seed test data bypassing RLS. + // This is required because: + // 1. Test data generation needs to create entities in protected tables + // 2. Moderator role is verified via is_moderator() RPC call before proceeding + // Scope: Limited to moderators only, for test/development purposes const supabaseUrl = Deno.env.get('SUPABASE_URL')!; const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!; const supabase = createClient(supabaseUrl, supabaseServiceKey);