JudgeFinder Platform - Complete Security Hardening
This directory contains comprehensive database security documentation and tools for the JudgeFinder Platform.
- Read the Security Guide:
docs/DATABASE_SECURITY_GUIDE.md - When creating a new table: Follow templates in the guide
- Always enable RLS:
ALTER TABLE ... ENABLE ROW LEVEL SECURITY;
- Review the Audit Report:
docs/security/SECURITY_AUDIT_REPORT.md - Apply the migration: See How to Apply
- Run verification:
psql -f scripts/verify_database_security.sql
- Read the Summary:
docs/security/SECURITY_HARDENING_SUMMARY.md - Check verification results: Run verification script
- Monitor advisors: Supabase Dashboard > Database > Advisors
Purpose: Comprehensive security audit report Size: 200+ lines Contains:
- Complete table inventory (60+ tables)
- RLS enablement status
- Policy coverage analysis
- SECURITY DEFINER vulnerability assessment
- Function search path audit
- Missing policies identification
- Verification queries
- Security recommendations
When to read: Before applying any security changes, for security reviews
Purpose: Executive summary of security work Size: 300+ lines Contains:
- Before/after security posture
- Files created/delivered
- Tables protected by new migration
- Existing security features validation
- How to apply changes
- Success criteria (all met ✅)
- Risk assessment
- Future recommendations
When to read: For project status updates, stakeholder communication
Purpose: Developer reference for RLS best practices Size: 500+ lines Contains:
- Quick reference for new tables
- 5 policy templates for common patterns
- Helper function documentation
- Common mistakes to avoid
- Testing procedures
- Migration checklist
- Monitoring procedures
- Emergency procedures
When to read: When creating new tables, implementing security features
Purpose: Automated security verification Size: 400+ lines Contains:
- 10 comprehensive security checks
- RLS enablement verification
- Policy coverage analysis
- SECURITY DEFINER function checks
- Overall security score calculation
When to run: Weekly for monitoring, after migrations, before deployments
20251017200000_enable_rls_all_tables.sql- Enabled RLS on 10 core tables20251018_service_role_access.sql- Service role access for core tables
20251017200100_create_rls_policies_part1.sql- app_users, judge_court_positions, sync_queue, pricing_tiers20251017200200_create_rls_policies_part2.sql- law_firm_targets, judge_analytics, case_attorneys, courthouse_analytics20251017200300_create_rls_policies_part3.sql- evaluations, documents
20251017200400_create_rls_policies_advertising.sql- 8 advertising tables with policies
20251009_002_complete_rls_coverage.sql- Additional tables (ad_waitlist, ad_events, etc.)
20251017200500_fix_security_definer_views.sql- Removed SECURITY DEFINER from 2 views20251017200600_add_function_search_paths.sql- Added search_path to key functions20251017210000_alter_all_function_search_paths.sql- Completed all 31 functions
Purpose: Complete RLS policy coverage for base schema tables Tables: users, attorneys, attorney_slots, bookmarks, search_history, subscriptions Policies: 32 total (5-6 per table) Status: Ready to apply
What it does:
- Enables RLS on 6 base schema tables (already enabled, ensures idempotency)
- Creates comprehensive policies for each table:
- Service role bypass (all tables)
- Admin full access (all tables)
- User-scoped access (user data tables)
- Public read (where appropriate)
- Adds inline comments
- Includes verification queries
| Category | Tables | RLS Enabled | Policies Complete | Status |
|---|---|---|---|---|
| Core Tables | 10 | 10/10 (100%) | 10/10 (100%) | ✅ Complete |
| CA Judicial | 13 | 13/13 (100%) | 13/13 (100%) | ✅ Complete |
| Elections | 3 | 3/3 (100%) | 3/3 (100%) | ✅ Complete |
| Advertising | 14 | 14/14 (100%) | 14/14 (100%) | ✅ Complete |
| Organizations | 7 | 7/7 (100%) | 7/7 (100%) | ✅ Complete |
| Analytics | 7 | 7/7 (100%) | 7/7 (100%) | ✅ Complete |
| Misc | 6 | 6/6 (100%) | 6/6 (100%) | ✅ Complete |
| TOTAL | 60 | 60/60 (100%) | 60/60 (100%) | ✅ Complete |
| Feature | Status | Count | Coverage |
|---|---|---|---|
| RLS Enabled | ✅ Complete | 60/60 | 100% |
| Tables with Policies | ✅ Complete | 60/60 | 100% |
| Service Role Bypass | ✅ Complete | 60/60 | 100% |
| Admin Access | ✅ Complete | 60/60 | 100% |
| SECURITY DEFINER Functions Protected | ✅ Complete | 31/31 | 100% |
| SECURITY DEFINER Views Fixed | ✅ Complete | 2/2 | 100% |
- Create table and enable RLS immediately:
CREATE TABLE my_new_table (...);
ALTER TABLE my_new_table ENABLE ROW LEVEL SECURITY;-
Choose appropriate template from
docs/DATABASE_SECURITY_GUIDE.md:- User-Scoped Data (bookmarks, search history)
- Public Read, Restricted Write (judges, courts)
- Organization-Scoped Data (campaigns, resources)
- Admin/Service Only (sync queues, audit logs)
- Public Insert, Restricted Read (analytics events)
-
Create policies using template:
-- Always include service role bypass
CREATE POLICY "Service role access" ON my_new_table
FOR ALL TO service_role USING (true) WITH CHECK (true);
-- Add specific access pattern
CREATE POLICY "Users manage own" ON my_new_table
FOR ALL TO authenticated
USING (user_id = auth.uid());- Test policies:
SET ROLE anon;
SELECT * FROM my_new_table; -- Should fail or return limited data
RESET ROLE;# Reset database (applies all migrations)
supabase db reset
# Or apply specific migration
supabase db push# Push to staging
supabase db push --project-ref <staging-project-id>
# Verify
psql -f scripts/verify_database_security.sql# IMPORTANT: Test in staging first!
# Push to production
supabase db push --project-ref <production-project-id>
# Verify immediately
psql -f scripts/verify_database_security.sql
# Monitor for access denied errors in application logs# Run full verification script
psql -f scripts/verify_database_security.sql-- Check RLS enablement (should return 0 rows)
SELECT tablename FROM pg_tables
WHERE schemaname = 'public' AND rowsecurity = false;
-- Check policy coverage (should return 0 rows)
SELECT t.tablename
FROM pg_tables t
LEFT JOIN pg_policies p ON p.tablename = t.tablename
WHERE t.schemaname = 'public'
AND t.rowsecurity = true
GROUP BY t.tablename
HAVING COUNT(p.policyname) = 0;
-- Check function protection
SELECT proname, proconfig
FROM pg_proc p
JOIN pg_namespace n ON p.pronamespace = n.oid
WHERE n.nspname = 'public' AND p.prosecdef = true;- Go to Supabase Dashboard
- Navigate to Database > Advisors
- Check for security warnings
- Expected: 0 warnings
# Add to cron or CI/CD
0 0 * * 1 psql -f /path/to/verify_database_security.sql | mail -s "Weekly Security Report" team@example.com- Run verification script
- Review security score
- Check for new tables without policies
- Update policies based on usage patterns
- Document any exceptions
- Monitor Supabase Dashboard > Database > Advisors
- Set up alerts for security warnings
- Track "access denied" errors in application logs
- Review audit logs for suspicious activity
Symptom: Application can't access data Cause: Missing or too restrictive policy Solution:
- Check which table is affected
- Review policies:
SELECT * FROM pg_policies WHERE tablename = 'table_name'; - Add missing policy or adjust USING clause
- Test with:
SET ROLE authenticated; SELECT * FROM table_name;
Symptom: Verification shows table without RLS Cause: New table created without RLS Solution:
ALTER TABLE table_name ENABLE ROW LEVEL SECURITY;
-- Then create policies
CREATE POLICY "Service role access" ON table_name
FOR ALL TO service_role USING (true) WITH CHECK (true);Symptom: Verification shows function without search_path Cause: Function created or altered without SET search_path Solution:
ALTER FUNCTION function_name() SET search_path = public, extensions;- Priority: P0 - CRITICAL
- Contact: Security team
- Response Time: Immediate
- Reference:
docs/DATABASE_SECURITY_GUIDE.md - Examples: Check existing migrations in
supabase/migrations/ - Team: Database/DevOps team
- Disable RLS: NEVER in production (use service role key for emergency access)
- Temporary Access: Add admin override policy
- Rollback: Revert migration and restore from backup
- Supabase RLS Docs: https://supabase.com/docs/guides/auth/row-level-security
- PostgreSQL RLS Docs: https://www.postgresql.org/docs/current/ddl-rowsecurity.html
- Security Best Practices: https://supabase.com/docs/guides/database/database-advisors
- Read
docs/DATABASE_SECURITY_GUIDE.md - Understand RLS concepts (policies, roles, USING/WITH CHECK)
- Review existing policies in migrations
- Know how to use helper functions (is_admin(), current_user_id())
- Bookmark this README for reference
- Run verification script to understand current state
- Ask questions before creating first table with RLS
- Monitor Supabase security advisors (automated)
- Run verification script
- Review access denied logs
- Full security audit
- Update policies based on usage
- Review new tables for RLS
- Security training for team
- Update documentation
- Review emergency procedures
Last Updated: October 24, 2025 Version: 1.0 Status: 🔒 Production Ready