Repository navigation
Stop signed-in users from squatting a workspace slug to block chat #409
Copy link
Copy link
Closed
Labels
ChatRelated to chat featuresRelated to chat featuresSecuritySecurity, access control, and data exposureSecurity, access control, and data exposurebugSomething isn't workingSomething isn't working
Milestone
Description
Activity
- added a parent issue
on Oct 6, 2026 - added a commit that references this issue
on 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:
select id, slug from public.workspaces where slug <> lower(id);
Generated by Claude Code
- added a commit that references this issue
on Oct 6, 2026 - 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 - addedChatRelated to chat featuresRelated to chat featuresSecuritySecurity, access control, and data exposureSecurity, access control, and data exposure
on Oct 6, 2026 - added a commit that references this issue
on 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.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.
Metadata
Metadata
Assignees
Labels
ChatRelated to chat featuresRelated to chat featuresSecuritySecurity, access control, and data exposureSecurity, access control, and data exposurebugSomething isn't workingSomething isn't working
Summary
The
workspaces_creator_insertpolicy lets any signed-in user insert aworkspacesrow with anyidand anyslug.slugis unique. If a user inserts a row whoseslugequals a target document's id (lowercase), every laterjoin_workspacefor that document fails on the unique key. Nobody can then join, so chat and Follow never start for that document.Production check (2026-10-06, read-only)
workspaces_creator_insert:FOR INSERT TO authenticated WITH CHECK (created_by = auth.uid()). No other check.authenticatedholds INSERT on everyworkspacescolumn, includingid,sluganddeleted_at.workspaces_pkey PRIMARY KEY (id),workspaces_slug_key UNIQUE (slug).Where
packages/supabase/scripts/13-RLS.sql:99-101(and its migration).join_workspacecreates the row withslug = lower(id):packages/supabase/scripts/10-functions.sql:861-867; latest migration bodypackages/supabase/migrations/20260708084510_owner_document_member_roster.sql:114-200.apps/webapp/src/hooks/useMapDocumentAndWorkspace.ts:68-71says a PostgREST insert "always 403s". That is false withPrefer: return=minimal.Fix plan
workspaces_creator_insertand revoke INSERT (and UPDATE) onpublic.workspacesfromauthenticatedandanon.join_workspace(DEFINER) is the only writer the app uses.createWorkspace,upsertWorkspaceandgetWorkspacesinapps/webapp/src/api/workspaces/have no importer. Delete them.useMapDocumentAndWorkspace.ts.workspacesrows whoseslugdiffers fromlower(id).packages/supabase/scripts/, then runbun run --filter @docs.plus/supabase_back types.Acceptance criteria
POST /rest/v1/workspacesis refused.join_workspace.select id, slug from workspaces where slug <> lower(id)returns no unexpected rows.Generated by Claude Code