DEV Community

Perufitlife
Perufitlife

Posted on

I shipped 5 BaaS security auditors in one day — keyless `npx --discover` mode for Supabase, PocketBase, Appwrite, Firebase, and Nhost

The story

A week ago I built supabase-security, a small Node.js auditor that scans Supabase projects for over-permissive RLS policies. To test it, I scanned 100 random Supabase projects from GitHub.

22 out of 100 leaked user data anonymously. The pattern was consistent: dashboard says "RLS enabled ✅", policies say USING (true), anonymous curl returns the full table.

Then I ran the tool against my own production CRM (FitCRM, an e-commerce ops platform I've been running for 2 years). Found 14 critical leaks. Order tables open to anon. Storage buckets with predictable signed URLs. RPCs with SECURITY DEFINER bypassing RLS.

I wrote the postmortem yesterday.

After that, two thoughts:

  1. If this many random Supabase projects leak, what about every other BaaS?
  2. The "keyless" mode (parse repo + probe anon, no admin creds) is the magic — anyone can run it on any project, including ones they don't own.

What I shipped today

Five sister tools. All MIT, all on npm, all use the same --discover pattern:

1. supabase-security v0.4

npx supabase-security@latest --discover .
Enter fullscreen mode Exit fullscreen mode

Parses from('table') / rpc('function') / storage.from('bucket') call sites, extracts SUPABASE_URL + SUPABASE_ANON_KEY from your repo, then probes the public REST API anonymously. Flags any table that returns rows.

2. pocketbase-security v0.2

npx pocketbase-security --discover .
Enter fullscreen mode Exit fullscreen mode

Parses pb.collection('name') call sites, then hits /api/collections/{name}/records anon. Catches the legendary PocketBase footguns: empty rules (= fully public), @request.auth.id != "" (any signed-up user passes), || true leftover dev rules.

3. appwrite-security v0.2

npx appwrite-security --discover .
Enter fullscreen mode Exit fullscreen mode

Parses databases.listDocuments(dbId, collId), probes /v1/databases/{db}/collections/{coll}/documents anon. Flags collections with the any role on Read permission, or users role with document security OFF.

4. firebase-security v0.2

npx firebase-security --discover .
Enter fullscreen mode Exit fullscreen mode

Parses collection(db, 'x') / doc(db, 'x/y'), extracts projectId from firebase config or env, then GETs firestore.googleapis.com/v1/projects/{pid}/databases/(default)/documents/{collection} anon. Confirms the legendary if true / wildcard-match-all leak pattern.

5. nhost-security v0.2

npx nhost-security --discover .
Enter fullscreen mode Exit fullscreen mode

Parses gql`queries for table names, auto-resolves the Hasura endpoint from subdomain+region (or env), POSTs anonymous queries against/v1/graphql. Flags tables where theanonymous` role has SELECT with permissive row filter.

The common pattern across every BaaS

Every BaaS has the same trap:

BaaS Footgun Dashboard says
Supabase USING (true) on RLS policy "RLS enabled ✅"
PocketBase Empty rule string "Public" (in tiny text)
Appwrite any role on Read Permissions "configured"
Firebase allow read: if true "Test mode"
Nhost anonymous role with {} filter "Permission configured"

In every case, the dashboard makes the configuration look intentional. In every case, anonymous curl returns rows. The dashboards don't show you what an anonymous-role evaluation actually returns — only what your role (the developer, signed in) returns.

Why "keyless --discover" is the unlock

Traditional security audits need admin credentials. The dev says "audit my Supabase" and hands you a service-role key. That's a high-trust ask and creates friction.

The keyless mode flips it:

  • Run npx <stack>-security --discover . from any project directory
  • It reads your client code (which already knows what tables/collections/buckets exist)
  • It probes the public API with the same anonymous credentials anyone on the internet has
  • No admin auth, no key sharing, no install

You can run it against your own project before pushing, or against a friend's project they're worried about, or in a CI step.

Patterns I'd add next

Things I want to detect but don't yet:

  • Cross-platform: Same project using Supabase + Stripe + Resend — credential leak in one breaks all three. Need a unified scanner.
  • JWT signature secrets committed to repos (already detectable via gitleaks but I want the BaaS-specific impact analysis)
  • Storage paths with predictable signed URLs — the FitCRM case
  • Function call sites with SECURITY DEFINER bypassing RLS — PostgREST anti-pattern
  • GraphQL introspection on Hasura instances exposing schema

Try it

Pick the stack you use most. The discover mode runs in seconds:

`bash
cd your-project
npx supabase-security --discover . # or pocketbase-security, etc
`

If you have a project worth a deeper audit, the paid $99 single-tenant audit report includes the manual review I did on my own CRM that found the SECURITY DEFINER RPCs and the predictable bucket paths. But the free CLI catches the common 70% of leaks.

Links

All MIT. If you find issues, open a PR. If you find a leak in your own project — fix it before someone else does.


If you run --discover on your project and want a second pair of eyes on the findings, I do one-off paid audits ($99 single project, $249 multi-tenant). But honestly, the CLI catches most of it.

Top comments (0)