All guides · Security

Security for AI-Built Apps: Supabase, Firebase and What a Scan Can’t See

AI app builders get a working product online in an afternoon. Most of them put the logic in the browser and connect it directly to a hosted backend such as Supabase or Firebase. That is a fine design, with one condition: the backend’s access rules must decide what each visitor may read and change, because the browser code can be read and edited by anyone.

An outside scan like ours sees the page, its headers and the keys it ships. It can’t log in, so it can’t see whether a stranger can read your users’ rows. Those checks are yours to run, and they take about an hour.

What we check from outside

  • Which builder and backend the page uses, from its domain and the code it loads.
  • Secret keys in the page: a Supabase service_role or sb_secret_ key, Stripe or Clerk secret keys, AI provider keys (OpenAI, Anthropic, Groq, xAI, Hugging Face, Replicate). A secret key in the browser gives anyone full access, whatever your rules say.
  • Payments in test mode: a Stripe pk_test_ key on the live site.
  • Published source maps: your original code, readable by anyone.

What to check yourself

1. Database access rules

  • Supabase: turn on Row Level Security for every table in the exposed schemas, then add policies. A table with RLS off is readable and writable by anyone holding the public anon key, and that key is in your page by design. Open the Security Advisor in the Supabase dashboard; it lists tables without RLS.
  • Policies should compare the row’s owner with auth.uid(). A policy like using (true) or “any signed-in user” lets every user read everyone’s data.
  • Users must not be able to update their own role, plan or credits columns. Keep those in a table only the server writes, or limit updates to the columns users may change.
  • Firebase: rules such as allow read, write: if true; or if request.auth != null are open to the world or to every signed-up user. Match each document to request.auth.uid, and test the rules in the Rules Playground or the emulator.

2. Storage buckets

Files users upload (invoices, ID photos, avatars) belong in private buckets with policies like the tables. Public buckets are for files everyone may see.

3. Keys and functions

  • Only the anon or publishable key belongs in the browser. Service keys, payment secret keys and AI keys live in server-side functions (Supabase Edge Functions, Firebase Functions, your API).
  • Database functions (rpc) run with the rights they are defined with: check that each one checks who is calling it.

4. Payments and paid features

  • Verify webhook signatures and ignore events you have already processed.
  • Take prices from your server or the payment provider, never from the browser.
  • Decide “is this user paying?” on the server for every paid feature, not by hiding buttons.

5. AI and other costly endpoints

An endpoint that calls an AI model with your key needs a login, a rate limit and a spending cap, or someone can run up your bill.

Test it like a stranger

Create a second account and, in the browser’s console, try to read and change the first account’s data with the same client library your app uses. Then try again signed out. Anything that works there works for everyone.

Last updated October 30, 2026