Supabase Security Report

Project: rotate (wpqnaardeaqgvllichui)

Region: us-east-1 · Scanned: 5/12/2026, 5:48:18 AM

F
Score: 0/100
0
Critical
5
High
7
Medium
36
Low/Info
▸ Active anon-key probe ran on 0 suspected leak(s). 0 confirmed.

Coverage

142
Tables scanned
15
SECURITY DEFINER functions
1
Storage buckets

Findings by severity

Findings (48)

[HIGH] SECURITY DEFINER function executable by anon

high

Target: refresh_achievement_stats

Function runs with creator privileges. If buggy, escalates to admin.

Details
{
  "returns": "void"
}
Fix SQL (copy & run in Supabase SQL editor)
REVOKE EXECUTE ON FUNCTION public.refresh_achievement_stats FROM anon;

[HIGH] SECURITY DEFINER function executable by anon

high

Target: fire_streak_milestone_feed

Function runs with creator privileges. If buggy, escalates to admin.

Details
{
  "returns": "void"
}
Fix SQL (copy & run in Supabase SQL editor)
REVOKE EXECUTE ON FUNCTION public.fire_streak_milestone_feed FROM anon;

[HIGH] SECURITY DEFINER function executable by anon

high

Target: community_search_similar

Function runs with creator privileges. If buggy, escalates to admin.

Details
{
  "returns": "TABLE(id uuid, title text, post_type text, is_answered boolean, comment_count integer, created_at timestamp with time zone, similarity real)"
}
Fix SQL (copy & run in Supabase SQL editor)
REVOKE EXECUTE ON FUNCTION public.community_search_similar FROM anon;

[HIGH] SECURITY DEFINER function executable by anon

high

Target: increment_answers_accepted

Function runs with creator privileges. If buggy, escalates to admin.

Details
{
  "returns": "void"
}
Fix SQL (copy & run in Supabase SQL editor)
REVOKE EXECUTE ON FUNCTION public.increment_answers_accepted FROM anon;

[HIGH] Storage bucket is public

high

Target: bucket:user-photos

Anyone can list and download all files in the bucket.

Details
{
  "id": "user-photos"
}
Fix SQL (copy & run in Supabase SQL editor)
UPDATE storage.buckets SET public = false WHERE id = 'user-photos'; -- only if you don't need public CDN-style access

[MEDIUM] SECURITY DEFINER function without SET search_path

medium

Target: fire_streak_milestone_feed

Function with mutable search_path can be hijacked: an attacker with CREATE on any schema in the path can shadow built-in functions and run arbitrary code as the function owner.

Details
{
  "returns": "void",
  "current_config": null
}
Fix SQL (copy & run in Supabase SQL editor)
ALTER FUNCTION public.fire_streak_milestone_feed SET search_path = public, pg_temp;

[MEDIUM] SECURITY DEFINER function without SET search_path

medium

Target: community_search_similar

Function with mutable search_path can be hijacked: an attacker with CREATE on any schema in the path can shadow built-in functions and run arbitrary code as the function owner.

Details
{
  "returns": "TABLE(id uuid, title text, post_type text, is_answered boolean, comment_count integer, created_at timestamp with time zone, similarity real)",
  "current_config": null
}
Fix SQL (copy & run in Supabase SQL editor)
ALTER FUNCTION public.community_search_similar SET search_path = public, pg_temp;

[MEDIUM] SECURITY DEFINER function without SET search_path

medium

Target: increment_answers_accepted

Function with mutable search_path can be hijacked: an attacker with CREATE on any schema in the path can shadow built-in functions and run arbitrary code as the function owner.

Details
{
  "returns": "void",
  "current_config": null
}
Fix SQL (copy & run in Supabase SQL editor)
ALTER FUNCTION public.increment_answers_accepted SET search_path = public, pg_temp;

[MEDIUM] Default privileges not revoked from anon/authenticated

medium

Target: schema:public (leaky owners: supabase_admin)

New tables you create will be auto-exposed. Supabase enforces this by Oct 30, 2026.

Details
{
  "leaky_owner_roles": [
    "supabase_admin"
  ],
  "note": "Supabase enforces revoke for all projects by Oct 30, 2026."
}
Fix SQL (copy & run in Supabase SQL editor)

-- Tables created via Supabase Dashboard (owner = supabase_admin) cannot be revoked from postgres role.
-- Toggle this in: Dashboard -> Project Settings -> Data API -> "Automatically expose new tables" = OFF
-- Or via Management API: PATCH /v1/projects/wpqnaardeaqgvllichui/postgrest with {"db_extra_search_path":"public", ...} (see docs).

[MEDIUM] Signups enabled without email confirmation

medium

Target: auth:signups

Anyone can create accounts and bypass email-gated logic.

Details
{
  "signups_enabled": true,
  "autoconfirm": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Dashboard: Auth -> Providers -> Email -> "Confirm email" = ON
-- API: PATCH /v1/projects/wpqnaardeaqgvllichui/config/auth body {"mailer_autoconfirm": false}

[MEDIUM] Weak password policy

medium

Target: auth:password

Minimum length below 8 characters. Use at least 8 + complexity requirements (digits/symbols).

Details
{
  "password_min_length": 6,
  "password_required_characters": null
}
Fix SQL (copy & run in Supabase SQL editor)
-- Dashboard: Auth -> Providers -> Email -> "Minimum password length" >= 8
-- API: PATCH /v1/projects/wpqnaardeaqgvllichui/config/auth body {"password_min_length": 12, "password_required_characters": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()"}

[MEDIUM] No CAPTCHA on auth endpoints

medium

Target: auth:captcha

Without CAPTCHA, signup/login forms can be brute-forced or spammed by bots.

Details
{
  "security_captcha_enabled": false
}
Fix SQL (copy & run in Supabase SQL editor)
-- Dashboard: Auth -> Settings -> Enable CAPTCHA (hCaptcha or Cloudflare Turnstile)
-- API: PATCH /v1/projects/wpqnaardeaqgvllichui/config/auth body {"security_captcha_enabled": true, "security_captcha_provider": "hcaptcha", "security_captcha_secret": "<your_secret>"}

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: aeo_h2_rewrites

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.aeo_h2_rewrites FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: ai_token_budget

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.ai_token_budget FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: auto_content_runs

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.auto_content_runs FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: b2b_leads

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.b2b_leads FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: b2b_outreach_log

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.b2b_outreach_log FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: bot_outbound_log

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.bot_outbound_log FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: community_bot_personas

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.community_bot_personas FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: community_bot_quarantine

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.community_bot_quarantine FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: community_bot_runs

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.community_bot_runs FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: community_bot_topic_history

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.community_bot_topic_history FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: digest_runs

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.digest_runs FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: engagement_emails

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.engagement_emails FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: growth_actions

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.growth_actions FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: growth_metrics

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.growth_metrics FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: growth_targets

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.growth_targets FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: growth_trending_topics

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.growth_trending_topics FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: gsc_queries

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.gsc_queries FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: messaging_webhook_events

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.messaging_webhook_events FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: owned_sub_content_calendar

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.owned_sub_content_calendar FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: owned_sub_invites

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.owned_sub_invites FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: owned_sub_member_snapshots

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.owned_sub_member_snapshots FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: owned_sub_posts

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.owned_sub_posts FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: owned_sub_welcomes

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.owned_sub_welcomes FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: owned_subreddit

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.owned_subreddit FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: programmatic_pages_queue

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.programmatic_pages_queue FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: query_position_history

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.query_position_history FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: reddit_actions

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.reddit_actions FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: reddit_opportunities

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.reddit_opportunities FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: reddit_subreddits

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.reddit_subreddits FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: scheduled_tweets

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.scheduled_tweets FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: seo_inspect_log

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.seo_inspect_log FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: seo_opportunity_queue

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.seo_opportunity_queue FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: seo_pages_status

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.seo_pages_status FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: translation_usage

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.translation_usage FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: tutor_question_categories

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.tutor_question_categories FROM anon, authenticated;

[LOW] RLS-locked table still has direct anon grants (defense-in-depth)

low

Target: winback_queue

Currently safe — RLS blocks all access. But if RLS is ever disabled by mistake, data leaks instantly. Best practice: revoke grants too.

Details
{
  "policies": 0,
  "anon_select": true,
  "auth_select": true
}
Fix SQL (copy & run in Supabase SQL editor)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.winback_queue FROM anon, authenticated;

Apply all fixes (single SQL script)

Copy and run in Supabase Dashboard → SQL Editor. Review each statement before executing.

-- SECURITY DEFINER function executable by anon (refresh_achievement_stats)
REVOKE EXECUTE ON FUNCTION public.refresh_achievement_stats FROM anon;

-- SECURITY DEFINER function executable by anon (fire_streak_milestone_feed)
REVOKE EXECUTE ON FUNCTION public.fire_streak_milestone_feed FROM anon;

-- SECURITY DEFINER function executable by anon (community_search_similar)
REVOKE EXECUTE ON FUNCTION public.community_search_similar FROM anon;

-- SECURITY DEFINER function executable by anon (increment_answers_accepted)
REVOKE EXECUTE ON FUNCTION public.increment_answers_accepted FROM anon;

-- Storage bucket is public (bucket:user-photos)
UPDATE storage.buckets SET public = false WHERE id = 'user-photos'; -- only if you don't need public CDN-style access

-- SECURITY DEFINER function without SET search_path (fire_streak_milestone_feed)
ALTER FUNCTION public.fire_streak_milestone_feed SET search_path = public, pg_temp;

-- SECURITY DEFINER function without SET search_path (community_search_similar)
ALTER FUNCTION public.community_search_similar SET search_path = public, pg_temp;

-- SECURITY DEFINER function without SET search_path (increment_answers_accepted)
ALTER FUNCTION public.increment_answers_accepted SET search_path = public, pg_temp;

-- Default privileges not revoked from anon/authenticated (schema:public (leaky owners: supabase_admin))

-- Tables created via Supabase Dashboard (owner = supabase_admin) cannot be revoked from postgres role.
-- Toggle this in: Dashboard -> Project Settings -> Data API -> "Automatically expose new tables" = OFF
-- Or via Management API: PATCH /v1/projects/wpqnaardeaqgvllichui/postgrest with {"db_extra_search_path":"public", ...} (see docs).

-- Signups enabled without email confirmation (auth:signups)
-- Dashboard: Auth -> Providers -> Email -> "Confirm email" = ON
-- API: PATCH /v1/projects/wpqnaardeaqgvllichui/config/auth body {"mailer_autoconfirm": false}

-- Weak password policy (auth:password)
-- Dashboard: Auth -> Providers -> Email -> "Minimum password length" >= 8
-- API: PATCH /v1/projects/wpqnaardeaqgvllichui/config/auth body {"password_min_length": 12, "password_required_characters": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()"}

-- No CAPTCHA on auth endpoints (auth:captcha)
-- Dashboard: Auth -> Settings -> Enable CAPTCHA (hCaptcha or Cloudflare Turnstile)
-- API: PATCH /v1/projects/wpqnaardeaqgvllichui/config/auth body {"security_captcha_enabled": true, "security_captcha_provider": "hcaptcha", "security_captcha_secret": "<your_secret>"}

-- RLS-locked table still has direct anon grants (defense-in-depth) (aeo_h2_rewrites)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.aeo_h2_rewrites FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (ai_token_budget)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.ai_token_budget FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (auto_content_runs)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.auto_content_runs FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (b2b_leads)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.b2b_leads FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (b2b_outreach_log)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.b2b_outreach_log FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (bot_outbound_log)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.bot_outbound_log FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (community_bot_personas)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.community_bot_personas FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (community_bot_quarantine)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.community_bot_quarantine FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (community_bot_runs)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.community_bot_runs FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (community_bot_topic_history)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.community_bot_topic_history FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (digest_runs)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.digest_runs FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (engagement_emails)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.engagement_emails FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (growth_actions)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.growth_actions FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (growth_metrics)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.growth_metrics FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (growth_targets)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.growth_targets FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (growth_trending_topics)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.growth_trending_topics FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (gsc_queries)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.gsc_queries FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (messaging_webhook_events)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.messaging_webhook_events FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (owned_sub_content_calendar)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.owned_sub_content_calendar FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (owned_sub_invites)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.owned_sub_invites FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (owned_sub_member_snapshots)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.owned_sub_member_snapshots FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (owned_sub_posts)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.owned_sub_posts FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (owned_sub_welcomes)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.owned_sub_welcomes FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (owned_subreddit)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.owned_subreddit FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (programmatic_pages_queue)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.programmatic_pages_queue FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (query_position_history)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.query_position_history FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (reddit_actions)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.reddit_actions FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (reddit_opportunities)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.reddit_opportunities FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (reddit_subreddits)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.reddit_subreddits FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (scheduled_tweets)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.scheduled_tweets FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (seo_inspect_log)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.seo_inspect_log FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (seo_opportunity_queue)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.seo_opportunity_queue FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (seo_pages_status)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.seo_pages_status FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (translation_usage)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.translation_usage FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (tutor_question_categories)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.tutor_question_categories FROM anon, authenticated;

-- RLS-locked table still has direct anon grants (defense-in-depth) (winback_queue)
-- Optional hardening: revoke direct grants to make leak impossible even if RLS is disabled.
REVOKE ALL ON public.winback_queue FROM anon, authenticated;
Generated by supabase-security · Open source (MIT) · Run locally, your token never leaves your machine.