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();