Skip to main content

Security audit

Is your app's database wide open?

Lovable, Bolt and v0 all reach for Supabase, and that's a good instinct — it's excellent software. But a Supabase table with row-level security switched off is readable by anyone who opens your app's network tab, and the AI that built your app has no way of knowing whether you meant to expose that data. This is the single most common serious defect we find, and it's usually a quiet one.

$495 fixed price · written report within 3 business days · no obligation to continue

In short

If your app uses Supabase and row-level security was never enabled, anyone can read and often write your tables directly — no login required. PixelApps audits AI-built Supabase apps for exactly this: open tables, missing policies, exposed service keys and public storage buckets. $495 fixed price, report in three business days.

Sound familiar?

If you recognise two or three of these, an audit will pay for itself.

  • Supabase is warning you and you've been ignoring it

    The dashboard has been flagging tables as unrestricted, or emailing you about publicly readable data.

  • Nobody ever wrote a policy

    The AI created tables and moved on. If you can't remember approving a security policy, one probably doesn't exist.

  • The service role key is in the front end

    The service key bypasses every security rule by design. In browser code, it hands full database access to anyone who looks.

  • Users can see each other's records

    The interface only shows people their own data, but the API underneath will happily return everyone's.

  • Uploads are in a public bucket

    Documents, invoices or ID photos sitting in storage that anyone with the URL pattern can fetch.

  • You're handling data you're accountable for

    Customer records, health information, payment details. Under the Australian Privacy Act a breach is your problem, not your tool's.

What is row-level security (RLS)?
Supabase exposes your Postgres database directly to the browser through an API, which is what makes it so fast to build with. Row-level security is the layer that decides which rows each user is allowed to see and change. If RLS is disabled on a table, that table is readable by anyone holding your public anon key — and that key is, by design, visible in your app's front-end code. Enabling RLS without writing policies is equally common, and locks everything out instead.

What we actually do

  1. We check every table

    Which tables have RLS enabled, which policies exist, and — more importantly — what those policies actually permit when someone tests them rather than reads them.

  2. We test it like an attacker would

    We take your public key and try to read and write data we shouldn't be able to. Theory is reassuring; a failed attempt is proof.

  3. We audit your keys and secrets

    Where each key lives, whether the service role key has escaped into the browser or the repository, and what needs rotating. Anything exposed gets replaced.

  4. We review storage and functions

    Bucket policies, signed URLs, and whether your edge functions verify who is calling them before they act.

  5. We write and test the policies

    Proper policies for every table, verified against real user scenarios, delivered as migrations in your repository so they're reviewable and repeatable.

What it costs

Everything is quoted at a fixed price before it starts. No hourly surprises.

Rescue audit

$495

fixed price

A senior developer reviews your codebase, database and deployment, and sends a written report within 3 business days.

Rescue sprint

$2,500 – $8,000

typical range

We fix what the audit found: security holes closed, the app stabilised, deployment sorted, and the parts that stopped you shipping actually finished.

Ongoing care

$750

from, per month

A monthly retainer: hosting, updates, security patches, backups, monitoring, an agreed block of development time, and a human who answers when something breaks. We also work ad-hoc — just ask.

What the $495 audit includes

  • A plain-English summary of what you have and what state it is in
  • Security review — database access rules, exposed keys, login and permissions
  • A prioritised list of what is broken, what is risky and what is merely untidy
  • A fixed-price quote for the work, and an honest view on rebuild vs repair
  • The report is yours to keep and take to any developer

When you don't need us

If your app has no real users and no real data, this can wait — go and build. But if there are customer records in that database, this is the one item on the list that can't wait, because the cost of getting it wrong isn't a broken feature, it's a notifiable data breach.

Send us your app

$495 fixed price. Written report within 3 business days.

Email

jayson@pixelapps.com.au

Location

Macedon Ranges, Victoria

Serving clients across Australia

Common questions

Open your Supabase dashboard and look at the table editor — tables without RLS enabled are flagged as unrestricted. That flag means anyone with your app's public anon key, which is visible in your front-end code, can query that table directly. If you see it, treat it as urgent.

Yes, and that's fine — it's designed to be visible. It's safe precisely because row-level security is supposed to be doing the actual protecting. Without RLS, that public key becomes a public database.

Every table's RLS status and policies, live testing against your API, key and secret exposure across your code and git history, storage bucket permissions, and edge function authorisation. You get a written report with each issue rated by severity and a fixed-price quote to fix it.

Yes. Most Supabase security work is a small, well-defined job once the audit has mapped it — policies written and tested, keys rotated, buckets locked down, delivered as migrations you keep in your repository.

We help you check the logs for what was actually queried and by whom, and walk you through your obligations under the Australian Privacy Act's notifiable data breaches scheme. Establishing the facts is the first step, and guessing is the worst one.