From 5b03de6b7e39d6943818558a556cbe4b7caf3478 Mon Sep 17 00:00:00 2001 From: DanielS Date: Thu, 9 Jul 2026 23:06:03 +0200 Subject: [PATCH] db: add strict rls policy to protect user roles from self-escalation --- .../20260709231000_secure_user_roles.sql | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 shop/supabase/migrations/20260709231000_secure_user_roles.sql diff --git a/shop/supabase/migrations/20260709231000_secure_user_roles.sql b/shop/supabase/migrations/20260709231000_secure_user_roles.sql new file mode 100644 index 0000000..a4b04c6 --- /dev/null +++ b/shop/supabase/migrations/20260709231000_secure_user_roles.sql @@ -0,0 +1,42 @@ +-- Migration: Secure User Roles from Self-Escalation +-- Purpose: Prevent users from updating their own roles to 'admin' using RLS / Triggers. + +-- Ensure RLS is enabled on users +ALTER TABLE public.users ENABLE ROW LEVEL SECURITY; + +-- Policy to allow users to view their own records +CREATE POLICY select_own_user ON public.users + FOR SELECT + TO authenticated + USING (auth.uid() = id); + +-- Policy to allow admins to view all users +CREATE POLICY select_all_users_for_admin ON public.users + FOR SELECT + TO authenticated + USING ( + (SELECT role FROM public.users WHERE id = auth.uid()) = 'admin' + ); + +-- Trigger to prevent any role updates to 'admin' from unauthorized users +CREATE OR REPLACE FUNCTION check_user_role_escalation() +RETURNS TRIGGER AS $$ +BEGIN + -- Only allow changes to the role column if executed by the service_role + IF (TG_OP = 'UPDATE' AND OLD.role IS DISTINCT FROM NEW.role) OR (TG_OP = 'INSERT') THEN + IF current_setting('role', true) <> 'service_role' THEN + -- Partners cannot upgrade themselves or others to admin + IF NEW.role = 'admin' THEN + RAISE EXCEPTION 'Unberechtigtes Rollen-Upgrade verweigert.'; + END IF; + END IF; + END IF; + RETURN NEW; +END; +$$ LANGUAGE plpgsql SECURITY DEFINER; + +DROP TRIGGER IF EXISTS enforce_role_protection ON public.users; +CREATE TRIGGER enforce_role_protection + BEFORE INSERT OR UPDATE ON public.users + FOR EACH ROW + EXECUTE FUNCTION check_user_role_escalation();