FixVibe

// docs / baas security / supabase rls scanner

Supabase RLS scanner: hanapin ang mga talahanayan na may nawawala o sirang row-level security

Ang Row-level security (RLS) lamang ang nakatayo sa pagitan ng data ng iyong mga customer at ng internet kapag nag-deploy ka ng app na nakabase sa Supabase. Ang mga AI coding tools ay gumagawa ng code na may hugis ng RLS na nakakapag-compile, nakakapag-deploy, at tahimik na nagle-leak ng data โ€” mga talahanayang ginawa na walang naka-enable na RLS, mga policy na nakakabasa pero hindi nagre-restrict, mga predicate na nagko-compare ng column sa sarili nito. Ipinapakita ng artikulong ito kung ano ang mapapatunayan ng Supabase RLS scanner mula sa labas, ang apat na hugis ng sirang RLS na lumilitaw sa mga vibe-coded apps, at kung paano i-scan ang iyong sariling deployment sa loob ng wala pang isang minuto.

Ano ang mapapatunayan ng panlabas na RLS scan

Ang passive RLS scan ay tumatakbo laban sa PostgREST endpoint na ine-expose ng Supabase sa https://[project].supabase.co/rest/v1/. Gumagamit lamang ito ng publishable anon key โ€” ang parehong key na ginagamit ng iyong browser โ€” at nagpo-probe para sa table-list metadata, anonymous reads, at anonymous writes. Hindi ito kailanman nag-a-authenticate bilang user at hindi kailanman humahawak sa service-role privileges. Anumang magagawa nito, magagawa rin ng isang unauthenticated attacker sa internet.

Mula sa labas ng database, may kakayahang kumpirmahin ng scanner ang sumusunod nang may mataas na tiwala:

  • Naka-disable ang RLS sa isang talahanayan. Nagbabalik ang PostgREST ng mga rows para sa isang anonymous na SELECT kapag patay ang RLS o kapag pinapayagan ito ng isang policy. Pareho itong finding.
  • Ang anonymous role ay makakapag-list ng mga talahanayan. Ang isang GET /rest/v1/ na may anon key ay nagbabalik ng OpenAPI schema para sa bawat talahanayan na may anumang privilege ang anon role dito. Madalas na nagbibigay ang mga AI-generated apps ng USAGE sa schema at SELECT sa bawat talahanayan, na nagpapakita ng buong schema map kahit na ipinagbabawal ng RLS ang aktuwal na pagbabasa.
  • Ang anonymous role ay makakapag-insert. Ang isang probing POST na may hula sa hugis ng column ay magtatagumpay kung walang INSERT policy ang RLS na ipinagbabawal ito โ€” kahit pa naka-lock ang SELECT.
  • Nasa browser bundle ang service-role key. Katabi ng RLS: kung makakita ang scanner ng SUPABASE_SERVICE_ROLE_KEY o anumang JWT na may role: service_role sa JavaScript bundle, walang kuwenta ang RLS โ€” sino mang humahawak ng key na iyon ay nakaka-bypass sa bawat policy.

Ano ang hindi mapapatunayan ng panlabas na scan

Maging tapat tungkol sa mga limitasyon ng scanner. Ang isang panlabas na RLS scan ay hindi makakabasa sa iyong pg_policies table, sa iyong migration files, o sa eksaktong predicate ng anumang policy. Naghihinuha ito mula sa black-box behaviour, na ibig sabihin minsan ay magre-report ito ng isang finding na pala-pala ay sinasadyang public data (isang marketing newsletter table, isang public product catalog). Inilalagay ng FixVibe report ang mga ito bilang medium confidence kapag hindi makapagpasya ang scanner kung ano ang intensiyon โ€” repasuhin ang pangalan ng talahanayan at magdesisyon.

Ang apat na hugis ng sirang RLS na gawa ng AI tools

Kapag tinuro mo ang Cursor, Claude Code, Lovable, o Bolt sa Supabase, ang parehong apat na sirang RLS patterns ay lumilitaw sa libu-libong apps. Ang bawat isa ay nakakapasa sa type-check, nakakapag-compile, at nakakapag-deploy:

Hugis 1: Hindi kailanman na-enable ang RLS

Ang pinakakaraniwang failure mode. Gumagawa ang migration ng talahanayan ngunit nakakalimutan ng developer (o ng AI tool) ang ALTER TABLE ... ENABLE ROW LEVEL SECURITY. Maligaya na pinaghahatid ng PostgREST ang buong talahanayan sa kahit sino na may anon key. Ayos: ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY; ALTER TABLE public.[name] FORCE ROW LEVEL SECURITY;. Hindi opsyonal ang FORCE โ€” kung wala ito, ang may-ari ng talahanayan (at anumang role na may table ownership) ay nakaka-bypass sa RLS.

sql
ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.[name] FORCE  ROW LEVEL SECURITY;

Hugis 2: Naka-enable ang RLS, walang policies

Mas banayad na failure. Naka-enable ang RLS pero walang policies na nakasulat. Ang default sa PostgreSQL ay deny, kaya walang nakikita ang mga authenticated users โ€” at idinadagdag ng developer ang USING (true) upang umubra ang app, na nagpapahintulot sa lahat na magbasa ng lahat. Ayos: magsulat ng policy na sakop ng auth.uid(): CREATE POLICY "select_own" ON public.[name] FOR SELECT USING (auth.uid() = user_id); at katumbas na INSERT/UPDATE/DELETE policy.

sql
CREATE POLICY "select_own"
  ON public.[name]
  FOR SELECT
  USING (auth.uid() = user_id);

Hugis 3: Ang policy ay nagko-compare ng column sa sarili nito

A copy-paste artefact. The developer writes <code>USING (user_id = user_id)</code> โ€” which is always true โ€” instead of <code>USING (auth.uid() = user_id)</code>. Type-checks pass; the policy permits every row. <strong>Fix:</strong> always compare a column to a function call (<code>auth.uid()</code>, <code>auth.jwt()->>'org_id'</code>, etc.), never to itself or to a constant.

Hugis 4: Policy sa SELECT pero wala sa INSERT/UPDATE

Ini-lock ng developer ang mga reads pero nakalimutan ang mga writes. Per-command ang mga RLS policies. Pinoprotektahan lang ng FOR SELECT ang mga reads; ang isang anonymous client ay maaari pa ring mag-INSERT kung walang policy na ipinagbabawal ito. Ayos: magsulat ng policy bawat command, o gumamit ng FOR ALL na may tahasang USING at WITH CHECK clauses.

Paano gumagana ang Supabase RLS scanner ng FixVibe

Ang baas.supabase-rls check ay tumatakbo sa tatlong yugto, bawat isa ay may tahasang antas ng tiwala:

  1. Yugto 1 โ€” fingerprint. Ine-crawl ng scanner ang naka-deploy na app, pina-parse ang JavaScript bundle nito, at kinukuha ang Supabase project URL at anon key mula sa runtime configuration. Walang DNS guessing, walang brute force โ€” binabasa nito kung ano ang binabasa ng browser.
  2. Yugto 2 โ€” schema discovery. Ang iisang GET /rest/v1/ na may anon key ay nagbabalik ng OpenAPI schema para sa bawat talahanayan na nakikita ng anon role. Itinatala ng scanner ang mga pangalan ng talahanayan pero hindi binabasa ang row data sa yugtong ito.
  3. Yugto 3 โ€” read and write probes. Para sa bawat natuklasang talahanayan, naglalabas ang scanner ng iisang anonymous na SELECT na may limit=1. Kung may bumalik na rows, permissive ang RLS. Doon huminto ang scanner โ€” hindi ito nag-e-enumerate ng rows, hindi nagpa-paginate, hindi nagmo-modify ng data. Ang mga INSERT probes ay nasa likod ng verified domain ownership at tahasang opt-in; hindi sila kailanman tumatakbo laban sa mga unverified targets.

Ang bawat finding ay may kasamang eksaktong request URL, response status, response shape (header-only), at ang pangalan ng talahanayan. Ang AI fix prompt sa ibaba ng finding ay isang copy-paste na SQL block na patatakbuhin mo sa Supabase SQL editor.

Ano ang gagawin kapag may nakita ang scanner

Ang bawat RLS finding ay isang runtime emergency. Ang mga pampublikong PostgREST endpoints ay ina-scan ng mga umaatake sa loob ng ilang minuto. Mekanikal ang remediation sequence:

  1. I-audit ang bawat talahanayan. Patakbuhin ang SELECT schemaname, tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public'; sa Supabase SQL editor. Ang bawat row na may rowsecurity = false ay isang problema.
  2. I-enable ang RLS sa bawat public na talahanayan. Mag-default sa ENABLE ROW LEVEL SECURITY at FORCE ROW LEVEL SECURITY sa bawat talahanayang ginawa โ€” gawin itong migration template.
  3. Magsulat ng policies bawat command. Huwag gamitin ang FOR ALL USING (true). Sumulat ng tahasang policies para sa SELECT, INSERT, UPDATE, DELETE โ€” bawat isa ay sakop ng auth.uid() o ng org-id column mula sa auth.jwt().
  4. I-verify gamit ang ikalawang account. Mag-sign up bilang ibang user, subukang basahin ang mga record ng ibang user sa pamamagitan ng REST API nang direkta. Kung ang response ay 200, sira ang policy.
  5. I-scan ulit. Pagkatapos i-apply ang fix, patakbuhin muli ang FixVibe scan laban sa parehong URL. Dapat nang mawala ang baas.supabase-rls finding.
sql
-- Audit every table for missing RLS. Run in the Supabase SQL editor.
SELECT schemaname, tablename, rowsecurity
FROM   pg_tables
WHERE  schemaname = 'public'
ORDER  BY rowsecurity, tablename;

Paano ito naihahambing sa ibang mga scanner

Ang karamihan ng generic DAST tools (Burp Suite, OWASP ZAP, Nessus) ay hindi nakakaalam kung ano ang PostgREST. Ina-crawl nila ang iyong app, binabalewala ang /rest/v1/ path, at nag-ulat sa mga HTML page na kanilang naiintindihan. Ang Snyk at Semgrep ay static-analysis tools โ€” nakakahanap sila ng mga migration files sa iyong repo na may nawawalang RLS calls, ngunit hindi nila mapapatunayan na maling konpigurado ang naka-deploy na database. Nakaupo ang FixVibe sa puwang na iyon: passive, BaaS-aware, nakatuon sa kung ano ang mapapatunayan ng isang unauthenticated attacker mula sa pampublikong URL.

Mga madalas na itinatanong

Babasahin o babaguhin ba ng scanner ang aking data?

Hindi. Ang passive scans ay naglalabas lamang ng pinakamadami na isang SELECT ... limit=1 bawat natuklasang talahanayan upang kumpirmahin kung pinapayagan ng RLS ang anonymous reads. Itinatala ng scanner ang hugis ng response, hindi ang nilalaman ng row. Ang mga INSERT, UPDATE, at DELETE probes ay nasa likod ng verified domain ownership at hindi kailanman tumatakbo laban sa mga unverified targets.

Gumagana ba ito kung naka-pause o nasa custom domain ang aking Supabase project?

Ang mga naka-pause na project ay nagbabalik ng 503 sa bawat request โ€” iniuulat ng scanner ang project bilang hindi naaabot. Gumagana ang mga custom domain hangga't naka-load pa rin ang Supabase client SDK sa browser ng naka-deploy na app; kinukuha ng scanner ang project URL mula sa bundle alinmang paraan.

Paano kung ang aking anon key ay na-rotate o nagbago ang publishable key ko?

Patakbuhin muli ang scan. Kinukuha muli ng scanner ang key mula sa kasalukuyang bundle sa bawat run. Inva-invalidate ng rotation ang nakaraang report lamang, hindi ang policy state ng database.

Sinusuri ba ng scanner ang bagong Supabase publishable-key model (<code>sb_publishable_*</code>)?

Oo. Kinikilala ng detector ang parehong legacy anon JWTs at ang mas bagong sb_publishable_* keys at pinapakitungo sila nang magkapareho โ€” pareho silang inilaan na maging pampubliko at parehong nag-iiwan sa RLS bilang tanging linya ng depensa.

Mga susunod na hakbang

Magpatakbo ng libreng FixVibe scan laban sa iyong production URL โ€” ang baas.supabase-rls check ay naka-enable sa bawat plan kasama ang free tier. Para sa mas malalim na pagbabasa kung ano pa ang maaaring tumagas mula sa isang Supabase project, tingnan ang Supabase service role key na naka-expose sa JavaScript at Supabase storage bucket security checklist. Para sa pangkalahatang tanaw sa lahat ng mga BaaS provider, basahin ang BaaS misconfiguration scanner.

// i-scan ang iyong baas surface

Hanapin ang bukas na talahanayan bago ito mahanap ng iba.

Ilagay ang isang production URL. Ine-enumerate ng FixVibe ang mga BaaS providers na kausap ng iyong app, kine-fingerprint ang kanilang mga pampublikong endpoints, at iniuulat kung ano ang mababasa o maisusulat ng isang unauthenticated client. Libre, walang install, walang card.

  • Libreng tier โ€” 3 scan / buwan, walang signup card.
  • Passive BaaS fingerprinting โ€” walang kailangang domain verification.
  • Supabase, Firebase, Clerk, Auth0, Appwrite, at iba pa.
  • Mga AI fix prompts sa bawat finding โ€” i-paste pabalik sa Cursor / Claude Code.
Supabase RLS scanner: hanapin ang mga talahanayan na may nawawala o sirang row-level security โ€” Docs ยท FixVibe