You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Stop signed-in users from squatting a workspace slug to block chat #409
The workspaces_creator_insert policy lets any signed-in user insert a workspaces row with any id and any slug. slug is unique. If a user inserts a row whose slug equals a target document's id (lowercase), every later join_workspace for that document fails on the unique key. Nobody can then join, so chat and Follow never start for that document.
Severity: Low
Area: Supabase
Source: security review of 2026-10-06
Production check (2026-10-06, read-only)
Policy workspaces_creator_insert: FOR INSERT TO authenticated WITH CHECK (created_by = auth.uid()). No other check.
authenticated holds INSERT on every workspaces column, including id, slug and deleted_at.
Policy: packages/supabase/scripts/13-RLS.sql:99-101 (and its migration).
join_workspace creates the row with slug = lower(id): packages/supabase/scripts/10-functions.sql:861-867; latest migration body packages/supabase/migrations/20260708084510_owner_document_member_roster.sql:114-200.
Misleading comment: apps/webapp/src/hooks/useMapDocumentAndWorkspace.ts:68-71 says a PostgREST insert "always 403s". That is false with Prefer: return=minimal.
Fix plan
Drop workspaces_creator_insert and revoke INSERT (and UPDATE) on public.workspaces from authenticated and anon. join_workspace (DEFINER) is the only writer the app uses.
Confirm no caller: createWorkspace, upsertWorkspace and getWorkspaces in apps/webapp/src/api/workspaces/ have no importer. Delete them.
Fix the comment in useMapDocumentAndWorkspace.ts.
Clean up any squatted rows: find workspaces rows whose slug differs from lower(id).
Mirror in packages/supabase/scripts/, then run bun run --filter @docs.plus/supabase_back types.
Acceptance criteria
A signed-in POST /rest/v1/workspaces is refused.
Opening a new document still creates its workspace and channel through join_workspace.
The query select id, slug from workspaces where slug <> lower(id) returns no unexpected rows.
changed the title [-][Security] Any signed-in user can squat a workspace slug and block chat for a target document[/-][+]Stop signed-in users from squatting a workspace slug to block chat[/+]on Oct 6, 2026
Reopened: the board automation closed this issue before the push. The code is on main through merge 083f37d84. It stays open until migration 20261006130000_close_client_write_and_grant_gaps.sql is applied on prod.
Deployed 2026-10-09 (run 37906965365, deploy job finished 09:28:41Z). Migration 20261006130000_close_client_write_and_grant_gaps.sql is applied on prod. Checked read-only: authenticated has no INSERT on workspaces.
Activity
fix(supabase): close client write and function grant gaps
HMarzban commentedon Oct 6, 2026
Fixed in
335138d: policy dropped, INSERT and UPDATE revoked, the three unused workspace API files removed, and the comment corrected.Not done on purpose: cleanup of squatted rows. It is a data change on production with no known rows. Run this read-only check by hand first:
Generated by Claude Code
docs: record the security and push fixes in changelogs and agent docs
[-][Security] Any signed-in user can squat a workspace slug and block chat for a target document[/-][+]Stop signed-in users from squatting a workspace slug to block chat[/+]chore(merge): land the security and push fixes branch
HMarzban commentedon Oct 9, 2026
Reopened: the board automation closed this issue before the push. The code is on
mainthrough merge083f37d84. It stays open until migration20261006130000_close_client_write_and_grant_gaps.sqlis applied on prod.HMarzban commentedon Oct 9, 2026
Deployed 2026-10-09 (run 37906965365, deploy job finished 09:28:41Z). Migration
20261006130000_close_client_write_and_grant_gaps.sqlis applied on prod. Checked read-only:authenticatedhas no INSERT onworkspaces.