Skip to content

Lock down SECURITY DEFINER functions, privileged columns and login redirects - #163

Merged
ralyodio merged 1 commit into
masterfrom
fix/secdef-lockdown
Oct 26, 2026
Merged

ralyodio merged 1 commit into
masterfrom
fix/secdef-lockdown

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Security audit 2026-10-26. 87 SECURITY DEFINER functions in public were executable by anon/authenticated.

Dangerous ones fixed

  • Internal, now service-role only: claim_call_analysis (anyone could claim queued call analyses and read the row), send_system_message (anon could post "system" messages with any name into any room), join_session_as_agent (caller-chosen p_owner_id), user_effective_plan / get_user_monthly_usage (other users' plan and usage), cleanup_expired_rooms, mark_stale_participants, prune_meeting_reminders, auto_promote_backup_host, bump_autoblog_integration, handle_new_user. All callers are cron, triggers or service-role routes.
  • start_media_session: any signed-in user could make themselves current host of any room. Now host only.
  • Default privileges: new functions are not executable by PUBLIC/anon/authenticated. A new RPC the browser calls (or an RLS helper) needs an explicit grant execute ... to anon, authenticated.
  • Update-own policies: pinned participant role/kind/agent owner/backup host/un-leave, session channel_id/org_id/team_id/creator_id/notify+recording stamps, profile email/created_at. Dropped the direct session_participants INSERT policy (unused by the app; it let users seat themselves past the plan caps).
  • /auth/callback?next= and the login ?redirect= accepted /\evil.com, which the URL parser resolves to https://evil.com/. New sameOriginPath() with tests.

Migration applied by hand on dev2 (schema backup first); live check with anon key and throwaway users: internal RPCs return 42501, host start/create/join/agent join still work, B cannot hijack, cannot self-promote, cannot insert, plan/email pinned. Remaining exposed: 75, all scoped to auth.uid() or public read-only data.

🤖 Generated with Claude Code

…directs

- Revoke 11 internal SECURITY DEFINER functions (call-analysis claim, cron
  cleanups, system chat messages, agent join with owner id, effective plan,
  monthly usage, autoblog bump, backup-host promotion, auth trigger) from
  anon/authenticated; service role keeps them.
- start_media_session: only the room's host may publish (any signed-in user
  could make themselves current host of any room).
- New functions are no longer executable by PUBLIC/anon/authenticated by
  default; browser RPCs need an explicit GRANT.
- Pin privileged columns behind the update-own policies: participant role,
  kind, agent owner, backup host, un-leave; session channel/org/team, creator
  and notify/recording stamps; profile email and created_at. Drop the direct
  session_participants INSERT policy (joins go through join_session, which
  enforces plan seat caps).
- Login and auth callback redirects rejected '//host' but not '/\\host',
  which the URL parser reads as another origin. Shared sameOriginPath()
  now rejects backslashes and control characters and checks the origin.

Migration applied by hand on dev2 (backup taken first).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

ThreatCrush Security Scan

50 finding(s)

HIGH/CRITICAL: 4 | MEDIUM: 28 | LOW: 18

Severity Rule Location
HIGH sh-eval-expansion .githooks/pre-commit:33
HIGH js-electron-node-integration apps/desktop/src/main/window.ts:49
HIGH sh-unquoted-expansion-destructive apps/installer/scripts/install.sh:717
HIGH sh-unquoted-expansion-destructive apps/installer/scripts/install.sh:921
MEDIUM sh-remote-script-execution apps/installer/scripts/install.sh:693
MEDIUM sh-remote-script-execution apps/installer/scripts/install.sh:824
MEDIUM sh-remote-script-execution apps/installer/scripts/install.sh:826
MEDIUM sh-remote-script-execution apps/installer/scripts/install.sh:1084
MEDIUM sh-remote-script-execution apps/installer/scripts/install.sh:1086
MEDIUM sh-remote-script-execution apps/livekit/setup-livekit-server.sh:93
MEDIUM sh-remote-script-execution apps/turn/deploy-droplet.sh:62
MEDIUM js-unescaped-html-sink apps/web/src/app/blog/[slug]/page.tsx:52
MEDIUM js-unescaped-html-sink apps/web/src/app/blog/[slug]/page.tsx:79
MEDIUM js-unescaped-html-sink apps/web/src/app/c/[handle]/page.tsx:199
MEDIUM js-open-redirect apps/web/src/app/cli/authorize/consent.tsx:68
MEDIUM js-unescaped-html-sink apps/web/src/app/l/[joinCode]/page.tsx:146
MEDIUM js-unescaped-html-sink apps/web/src/app/l/[joinCode]/page.tsx:230
MEDIUM js-unescaped-html-sink apps/web/src/app/layout.tsx:150
MEDIUM js-unescaped-html-sink apps/web/src/app/live/page.tsx:154
MEDIUM js-unescaped-html-sink apps/web/src/app/page.tsx:98
MEDIUM js-unescaped-html-sink apps/web/src/app/pricing/page.tsx:262
MEDIUM js-unescaped-html-sink apps/web/src/app/u/[username]/page.tsx:285
MEDIUM js-open-redirect apps/web/src/components/billing/useCheckout.ts:81
MEDIUM js-unescaped-html-sink apps/web/src/components/pit-footer.tsx:24
MEDIUM js-open-redirect apps/web/src/hooks/useDesktopHandoff.ts:24
MEDIUM redos-nested-quantifier apps/web/src/lib/deliverable.ts:11
MEDIUM js-unescaped-html-sink apps/web/src/lib/player/player.ts:124
MEDIUM js-unescaped-html-sink apps/web/src/lib/player/player.ts:393
MEDIUM js-unescaped-html-sink apps/web/src/lib/player/player.ts:396
MEDIUM js-unescaped-html-sink apps/web/src/lib/player/player.ts:405
MEDIUM js-unescaped-html-sink apps/web/src/lib/player/player.ts:608
MEDIUM sql-template-interpolation packages/ai-core/src/prompts.ts:36
LOW secret-generic-credential apps/desktop/src/main/agent-cli/commands.test.ts:138
LOW secret-generic-credential apps/desktop/src/main/agent-cli/commands.test.ts:139
LOW secret-generic-credential apps/desktop/src/main/agent-cli/commands.test.ts:340
LOW secret-generic-credential apps/desktop/src/main/agent-cli/commands.test.ts:341
LOW secret-generic-credential apps/desktop/src/main/agent-cli/commands.test.ts:371
LOW secret-generic-credential apps/desktop/src/main/agent-cli/commands.test.ts:372
LOW secret-generic-credential apps/desktop/src/main/agent-cli/commands.test.ts:383
LOW secret-generic-credential apps/desktop/src/main/agent-cli/commands.test.ts:397
LOW secret-generic-credential apps/desktop/src/main/agent-cli/commands.test.ts:398
LOW secret-generic-credential apps/desktop/src/main/agent-cli/commands.test.ts:405
LOW secret-generic-credential apps/desktop/src/main/agent-cli/commands.test.ts:415
LOW secret-generic-credential apps/desktop/src/main/agent-cli/commands.test.ts:416
LOW secret-generic-credential apps/desktop/src/main/agent-cli/commands.test.ts:453
LOW secret-generic-credential apps/desktop/src/main/agent-cli/commands.test.ts:454
LOW secret-generic-credential apps/livekit/fly.toml:12
LOW secret-generic-credential apps/turn/fly.toml:11
LOW secret-generic-credential docs/API.md:747
LOW secret-generic-credential docs/API.md:753

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio merged commit 94b5d2e into master Oct 26, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant