UPDATE policy was USING-only: a privileged caller could mutate a member row into a space they don't administer (no post-image re-check). Migration 043 adds the mirrored WITH CHECK. Self column escalation (space_id/role/status) remains blocked by the trigger (D9). Schema + DB maps updated.
24 lines
1.2 KiB
SQL
24 lines
1.2 KiB
SQL
-- =============================================================================
|
|
-- 043: space_members UPDATE — add WITH CHECK (defense-in-depth)
|
|
-- =============================================================================
|
|
-- members_update had only a USING clause: a privileged caller could mutate a
|
|
-- member row into a space where they hold no role (cross-space move) because
|
|
-- the post-image was never re-checked. Add a WITH CHECK mirroring the USING
|
|
-- so the resulting row must still satisfy the same predicate. (Self column
|
|
-- escalation -- space_id/role/status -- is separately blocked by the
|
|
-- prevent_member_self_role_change trigger; see scripts/044.)
|
|
--
|
|
-- Idempotent: DROP POLICY IF EXISTS then CREATE.
|
|
-- =============================================================================
|
|
|
|
DROP POLICY IF EXISTS members_update ON public.space_members;
|
|
CREATE POLICY members_update ON public.space_members FOR UPDATE
|
|
USING (
|
|
user_id = auth.uid()
|
|
OR public.user_has_role_in_space(auth.uid(), space_id, ARRAY['admin','board','treasurer'])
|
|
)
|
|
WITH CHECK (
|
|
user_id = auth.uid()
|
|
OR public.user_has_role_in_space(auth.uid(), space_id, ARRAY['admin','board','treasurer'])
|
|
);
|