Skip to content

RLS policies implementation#95

Open
Swayymalcolm99 wants to merge 3 commits into
StepFi-app:mainfrom
Swayymalcolm99:main
Open

RLS policies implementation#95
Swayymalcolm99 wants to merge 3 commits into
StepFi-app:mainfrom
Swayymalcolm99:main

Conversation

@Swayymalcolm99

@Swayymalcolm99 Swayymalcolm99 commented Jul 20, 2026

Copy link
Copy Markdown

Closes #32
Summary

This PR introduces Row Level Security (RLS) for Supabase to strengthen database security by restricting user access to only their own records. It lays the foundation for enforcing wallet-scoped authorization while preserving service-role access for trusted backend operations.

Why

Previously, database access relied primarily on the service-role client, which bypasses RLS entirely. This created a security gap where user-facing operations were not protected by database-level authorization.

This PR introduces the necessary database policies and client infrastructure required to support secure, wallet-scoped access.

Changes

Database

  • Enabled RLS on the required Supabase tables.
  • Added RLS policies for:
    • "learner_profiles"
    • "loans"
    • "vouches"
    • "vendors"
    • "liquidity_positions"
    • "sponsor_pools"
  • Added the "set_app_current_wallet(wallet)" RPC function for wallet-based authorization.
  • Removed overly permissive write policies that could allow unrestricted writes.

Service Layer

  • Added "getWalletScopedClient()" to return an anonymous Supabase client that respects RLS policies.
  • Preserved the existing service-role client for administrative and indexer operations that intentionally bypass RLS.

Testing

  • Verified that the migration executes successfully.
  • Verified that RLS policies are created for the target tables.
  • Confirmed the wallet-scoped client can be instantiated successfully.
  • Confirmed service-role operations remain unaffected.

@EmeditWeb EmeditWeb left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review verdict: ❌ Request changes (security)

RLS as defense-in-depth is the right idea, but as submitted these policies do not protect anything and one pattern is an active footgun.

1. Not enforced for any application traffic. The migration header says "The API layer sets a Postgres session variable app.current_wallet before making queries." It doesn't — there is no SET LOCAL app.current_wallet / set_config anywhere in src/. And the API uses the service-role client (src/database/supabase.client.ts:52), which bypasses RLS entirely. So the checked acceptance criterion "Users can only access their own data — MET" is not accurate; the policies are inert for the running app.

2. Blanket-permissive write policies (footgun). The file has 8 policies using WITH CHECK (true) / USING (true), e.g.:

CREATE POLICY "Service role can insert loans" ON public.loans FOR INSERT WITH CHECK (true);
CREATE POLICY "Service role can update loans" ON public.loans FOR UPDATE USING (true);

Service role bypasses RLS, so these true policies don't apply to service role — they apply to non-service-role sessions, i.e. exactly the sessions RLS should restrict. The moment any non-service path exists (the whole premise of adding RLS), any user could insert/update any loan/position. To restrict writes to service role, write no policy for other roles and rely on the bypass — don't add USING(true).

3. RLS may not be enabled on all target tables. Prior migrations enable RLS on loans/nonces/liquidity_positions, but I don't see ENABLE ROW LEVEL SECURITY for learner_profiles/vouches/vendors/sponsor_pools — their policies would be dormant. Please verify/add.

4. Scope creep: edits .github/PULL_REQUEST_TEMPLATE.md (+59/-20), unrelated to RLS.

To move forward: add a request-scoped, non-service-role DB client that runs SET LOCAL app.current_wallet = $wallet per authenticated request; delete the 8 true write policies; add ENABLE ROW LEVEL SECURITY on the uncovered tables; drop the template edit.

@Swayymalcolm99

Copy link
Copy Markdown
Author

Removed 8 blanket-permissive write policies - Deleted WITH CHECK (true) / USING (true) policies that were security footguns
Added ENABLE ROW LEVEL SECURITY - Explicitly enabled RLS on learner_profiles, vouches, vendors, and sponsor_pools
Created RPC function - Added set_app_current_wallet(wallet) to set Postgres session variable for RLS enforcement
Updated SupabaseService - Added getWalletScopedClient() and setWalletSessionVariable() for wallet-scoped queries that respect RLS

@Swayymalcolm99

Copy link
Copy Markdown
Author

Summary
Implements Row Level Security (RLS) policies for Supabase tables to prevent unauthorized data access. This adds defense-in-depth security by ensuring users can only access their own data, while service role operations bypass RLS for admin/indexer tasks.

Changes:
Database Migration (20260718000000_rls_policies.sql)
Enabled RLS on learner_profiles, vouches, vendors, and sponsor_pools
Created RLS policies for 6 tables: learner_profiles, loans, vouches, vendors, liquidity_positions, sponsor_pools
Added RPC function set_app_current_wallet(wallet) to set Postgres session variable for RLS enforcement
Removed blanket-permissive write policies (security footgun that would allow any user to write anything)
Service Layer (supabase.client.ts)
Added getWalletScopedClient() method that returns anon-key client (respects RLS) instead of service-role client (bypasses RLS)
Security Notes
The current API uses the service-role client which bypasses RLS entirely. The infrastructure is now in place for the API layer to transition to wallet-scoped clients for user-facing queries. To fully enable RLS enforcement, services should:
Use supabaseService.getWalletScopedClient() instead of getServiceRoleClient() for user queries
Call client.rpc('set_app_current_wallet', { wallet: walletAddress }) before queries

@EmeditWeb

Copy link
Copy Markdown
Member

Your PR Summary structure is poor and doesn't follow standards, please rework on it.

@Swayymalcolm99

Copy link
Copy Markdown
Author

I just updated the pr now and gave it a proper structure

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.

core: implement Supabase Row Level Security for all tables

3 participants