From 1efd787a95b4d04c7050cd4b508e062e69a474ca Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 15:51:12 +0000 Subject: [PATCH] Apply database migration for security fixes --- ...9_650b12b2-e3c8-48e7-8d03-3116b05e9fdb.sql | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 supabase/migrations/20251103155059_650b12b2-e3c8-48e7-8d03-3116b05e9fdb.sql diff --git a/supabase/migrations/20251103155059_650b12b2-e3c8-48e7-8d03-3116b05e9fdb.sql b/supabase/migrations/20251103155059_650b12b2-e3c8-48e7-8d03-3116b05e9fdb.sql new file mode 100644 index 00000000..9060de3a --- /dev/null +++ b/supabase/migrations/20251103155059_650b12b2-e3c8-48e7-8d03-3116b05e9fdb.sql @@ -0,0 +1,78 @@ +-- ============================================================================ +-- CRITICAL SECURITY FIXES (P0) +-- ============================================================================ + +-- Fix #1: Profiles Table PII Exposure - Remove anon access +DROP POLICY IF EXISTS "Public can view non-banned public profiles" ON public.profiles; + +CREATE POLICY "Profiles restricted to authenticated users and moderators" +ON public.profiles +FOR SELECT +TO authenticated +USING ( + auth.uid() = user_id + OR is_moderator(auth.uid()) +); + +GRANT SELECT ON public.filtered_profiles TO anon; + +COMMENT ON POLICY "Profiles restricted to authenticated users and moderators" ON public.profiles IS +'SECURITY: Restricts direct profile table access to profile owners and moderators only. Anonymous users must use filtered_profiles view.'; + +-- Fix #2: User_roles Table - Ensure no public access +ALTER TABLE public.user_roles ENABLE ROW LEVEL SECURITY; + +DROP POLICY IF EXISTS "user_roles are viewable by everyone" ON public.user_roles; +DROP POLICY IF EXISTS "Public can view user roles" ON public.user_roles; +DROP POLICY IF EXISTS "Users can view their own roles" ON public.user_roles; + +CREATE POLICY "Users can view their own roles only" +ON public.user_roles +FOR SELECT +TO authenticated +USING (auth.uid() = user_id); + +CREATE POLICY "Moderators can view all roles with MFA" +ON public.user_roles +FOR SELECT +TO authenticated +USING (is_moderator(auth.uid())); + +-- Fix #3: Error_summary View - Set SECURITY INVOKER +DROP VIEW IF EXISTS error_summary; + +CREATE VIEW error_summary +WITH (security_invoker = true) +AS +SELECT + error_type, + endpoint, + COUNT(*) as occurrence_count, + COUNT(DISTINCT user_id) as affected_users, + MAX(created_at) as last_occurred, + MIN(created_at) as first_occurred, + ROUND(AVG(duration_ms)::numeric, 2) as avg_duration_ms, + (ARRAY_AGG(request_id ORDER BY created_at DESC) + FILTER (WHERE created_at > now() - interval '1 day') + )[1:5] as recent_request_ids +FROM request_metadata +WHERE error_type IS NOT NULL + AND created_at > now() - interval '30 days' +GROUP BY error_type, endpoint +ORDER BY occurrence_count DESC; + +DROP POLICY IF EXISTS "Moderators can view error metadata" ON request_metadata; + +CREATE POLICY "Moderators can view error metadata" +ON request_metadata +FOR SELECT +TO authenticated +USING ( + is_moderator(auth.uid()) + OR user_id = auth.uid() +); + +GRANT SELECT ON error_summary TO authenticated; + +COMMENT ON VIEW error_summary IS +'Error aggregation view with SECURITY INVOKER - uses caller permissions.'; \ No newline at end of file