Skip to content

security: enable RLS on public tables + fix cross-program IDOR#182

Merged
sacha-l merged 1 commit into
developfrom
fix/security-rls-and-idor
Jun 16, 2026
Merged

security: enable RLS on public tables + fix cross-program IDOR#182
sacha-l merged 1 commit into
developfrom
fix/security-rls-and-idor

Conversation

@sacha-l

@sacha-l sacha-l commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Security fixes from an audit triggered by the Supabase "RLS Disabled in Public" advisor. One fix (RLS) is already applied to prod; this PR puts it in the repo and adds the IDOR fix.

1. RLS disabled on public tables (P0, exploited verified)

The Supabase Data API (PostgREST) exposed every public table to the anon key — which ships in the client bundle — for read and write. Verified against prod with the live anon key: GET /projects returned real rows, DELETE /projects and PATCH /program_admins returned 204 (privilege present). That bypasses the Express server's entire auth layer.

Fix: enable RLS (deny-by-default, no policies) on all public tables. Safe with zero functional impact here because the server uses the SERVICE_ROLE key (BYPASSRLS) and the client uses Supabase only for auth, never table queries. Verified post-fix: anon now gets []; Express server unaffected.

2. Cross-program IDOR in updateApplicationStatus (HIGH)

PATCH /programs/:slug/applications/:applicationId updated by id without checking the application belonged to :slug's program — a program-A admin could mutate program-B applications. Now fetches the application and asserts programId match before any write (404 otherwise). Added IDOR + not-found tests.

Verification

429 server tests pass (replaced 1 obsolete best-effort-lookup test with 2 scoping tests). Prod anon access re-probed → closed.

⚠️ Out-of-band action required (cannot fix in code)

server/.env was committed in history (670b2bc) and removed (c44a048) — it contained a live MongoDB Atlas URI (jasonholt2002@hackathon0…mongodb.net). The Supabase service-role key was NOT in it. Rotate that Atlas password / delete the DB user; optionally purge it from history (BFG/filter-repo). Tracked separately from this PR.

… status update

1) RLS: the Supabase Data API exposed every public table to the anon key
   (shipped in the client bundle) for read AND write — verified anon could
   SELECT/DELETE/UPDATE projects, program_admins, multisig_*. Enable RLS
   (deny-all) on all public tables; server uses service_role (BYPASSRLS) and
   the client only uses Supabase auth, so zero functional impact. Already
   applied to prod; committing so repo history matches.

2) IDOR: updateApplicationStatus updated by applicationId without verifying it
   belongs to the program in the slug, letting a program-A admin mutate
   program-B applications. Now fetch + assert programId match before any write.

429 server tests pass.
@vercel

vercel Bot commented Jun 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
stadium Ready Ready Preview, Comment Jun 16, 2026 10:03pm

@sacha-l sacha-l marked this pull request as ready for review June 16, 2026 23:00
@sacha-l sacha-l merged commit 871f312 into develop Jun 16, 2026
2 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