Repository navigation
security: pin managed-number + org plan columns, default privileges, tab-redirect bypass - #112
Merged
Merged
Conversation
…CUTE, close tab-redirect bypass Migration applied to prod by hand. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ThreatCrush Security Scan12 finding(s) HIGH/CRITICAL: 2 | MEDIUM: 4 | LOW: 6
Snippets are redacted; ThreatCrush never prints matched credential material. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
From the 2026-10-26 fleet SECURITY DEFINER audit (
smshub-dev-supabase-db).Functions: 4 exposed, 0 dangerous.
is_org_admin,is_org_member,is_team_memberandis_team_owneronly answer forauth.uid(), and the RLS policies use them, so they keep their grants. Default privileges no longer grant EXECUTE on new functions to anon/authenticated, and trigger functions are revoked.Privileged columns (rule 10):
phone_numbers.telnyx_number_idcould be rewritten by the owner of a managed number. The expiry job (service.ts) releases whatever Telnyx id the row carries, so pointing a lapsing number at another customer's id would release their number. That column andreleased_atare now pinned, and so are the existing fields. Aprovider_idchange must name one of the caller's own providers.phone_numbersvia PostgREST skipped everythingPOST /api/phone-numberschecks: provider ownership, the BYO plan limit and the "already connected" check. The API already inserts with the service role, so direct inserts are now refused. Friendly-name edits through the user client still work.organizations.planwas writable by org admins. It is display only, because the real plan comes from managed numbers, but it is now pinned to the server.Open redirect:
safeNextPathaccepted/\t/evil.example. The URL parser strips the tab, which leaves//evil.example. So/auth/callback?next=/%09/evil.exampleand the login page'srouter.push(next)both went off-site. Control characters and backslashes are now refused, and the result must resolve same-origin. Tests added.Applied to prod by hand after a schema backup and a rolled-back dry run (simulated authenticated user: friendly_name update ok, telnyx id change refused, direct insert refused), followed by
notify pgrst.Not fixed, functional bug only: creating an org from
/orgcan't work. The client inserts intoorganizationsand then intoorg_members, and both policies requireis_org_adminof an org that has no members yet. There are 0 orgs in prod.Tests: vitest 52 files / 320 passed, tsc clean.
🤖 Generated with Claude Code