Rustine

Secure your Supabase app, without being a developer

Updated on 15 October 2026 · 3 min

Contents

Your Supabase anon key sits in your site's JavaScript, and that's fine: it's meant to be public. What protects your data is your database's rules. Here are the six places where they give way most often, how to see it yourself, and what Rustine checks for you.

At a glance

RiskWhere Rustine checks it
A table without RLSFull audit · Solo, ProSupabase connected · Solo, ProGitHub code · Solo, Pro
A using (true) policyFull audit · Solo, ProSupabase connected · Solo, ProGitHub code · Solo, Pro
The service_role key in the browserFree scanGitHub code · Solo, Pro
Public bucketsFull audit · Solo, ProSupabase connected · Solo, ProGitHub code · Solo, Pro
Open RPC functionsGitHub code · Solo, Pro
Sign-ups left too openFull audit · Solo, ProSupabase connected · Solo, Pro

1. A table without RLS

Without Row Level Security, the anon key is enough to read, change and delete the table's rows through the API. Every visitor has that key.

Check it yourself

In your Supabase dashboard, open Advisors, then Security Advisor. The “RLS Disabled in Public” error lists the tables. Turn RLS on for each one, then write its policies.

What Rustine checks

After proof, the full audit counts the rows the anon key lets anyone read, table by table, without reading a single one. With Supabase connected, Rustine reads each table's RLS state. On GitHub, it spots migrations that create a table without RLS.

Full audit · Solo, ProSupabase connected · Solo, ProGitHub code · Solo, Pro

Sources: [1][2]

2. A using (true) policy

RLS is on, the padlock shows, but the policy says “yes” to everyone. The table stays open. It's often what an AI agent writes to “make a query work”.

Check it yourself

The Security Advisor shows it as a warning: “Permissive RLS policy”. Then read each table's policies in the dashboard: using (true) or with check (true) with no other condition opens the table to all.

What Rustine checks

With Supabase connected, Rustine reads every policy and reports those set to using (true) or with check (true). The full audit sees the effect, a table readable with the anon key. On GitHub, it spots them in your migrations.

Full audit · Solo, ProSupabase connected · Solo, ProGitHub code · Solo, Pro

Sources: [1][2]

3. The service_role key in the browser

The service_role key, like sb_secret_ secret keys, bypasses RLS. In your site's JavaScript, it hands your whole database to anyone who opens the console.

Check it yourself

In your code, search for SERVICE_ROLE and sb_secret_. They must live on the server only (Edge Functions), never in a variable starting with VITE_ or NEXT_PUBLIC_. If one was published, rotate it in Supabase right away.

What Rustine checks

From the free scan, Rustine looks for a service_role or sb_secret_ key in the JavaScript your site serves. On GitHub, it spots a public variable holding it.

Free scanGitHub code · Solo, Pro

Sources: [3][4]

4. Public buckets

A file in a public bucket opens with its address alone, with no access control. Invoices, ID scans or exports have no business there.

Check it yourself

In Storage, look for buckets marked Public. The Security Advisor adds “Public bucket allows listing” when their files can also be listed.

What Rustine checks

After proof, the full audit checks whether the bucket list can be read and flags public buckets with a sensitive name, without opening a file. With Supabase connected, it lists all your public buckets. On GitHub, it spots Storage policies that are too broad.

Full audit · Solo, ProSupabase connected · Solo, ProGitHub code · Solo, Pro

Sources: [5][1]

5. Open RPC functions

A function of your database can be called through the API, by default even without signing in. As security definer, it runs with its creator's rights and can return rows RLS hides.

Check it yourself

In your database's list of functions, look for security definer functions. For each one, ask whether a signed-out visitor should be able to call it. If not, revoke execute from the anon role: Supabase's documentation gives the command.

What Rustine checks

On GitHub, Rustine spots security definer functions exposed in your migrations. From the site, it isn't checked yet.

GitHub code · Solo, Pro

Sources: [6]

6. Sign-ups left too open

Sign-up without email confirmation, anonymous sign-ins on, passwords too short: these are settings, not code, and they get forgotten.

Check it yourself

In the authentication settings, check that email confirmation is on, that anonymous sign-ins are off if you don't use them, and that leaked password protection is on.

What Rustine checks

After proof, the full audit flags open sign-ups without email confirmation. With Supabase connected, it adds anonymous sign-ins, minimum password length, captcha and leaked passwords.

Full audit · Solo, ProSupabase connected · Solo, Pro

Sources: [1]

Scan your site, it's free

Paste your address: the quick scan reads what a visitor sees, nothing more. The details show once you've proven the site is yours.

No site? Analyse your GitHub code

Free toolsSupabase checkerSecurity headers test

Questions

Is the Supabase anon key a secret?

No. Supabase designs it to be public: it only opens what your policies allow. The danger is a table without RLS or a policy that's too broad, not the key.

Isn't Supabase's Security Advisor enough?

It's a very good start: it sees your database from the inside. Rustine adds what your site actually exposes, such as a service_role key in your JavaScript or a live .env file, and what a visitor can read with your anon key.

Does Rustine read my data?

No. The audit counts readable rows without downloading them. The Supabase connection asks for read rights on your configuration, never your service_role key.

Sources

  1. Supabase, Performance and Security Advisors, read on 15/10/2026
  2. Supabase, Row Level Security, read on 15/10/2026
  3. Supabase, Understanding API keys, read on 15/10/2026
  4. Vite, Env Variables and Modes, read on 15/10/2026
  5. Supabase, Storage Buckets, read on 15/10/2026
  6. Supabase, Database Functions, read on 15/10/2026