DEV Community

Perufitlife
Perufitlife

Posted on

I shipped 8 BaaS security scanners on Apify in 9 days — the single-file pattern that made it possible

I shipped 8 BaaS security scanners on Apify in 9 days — here's the pattern that lets one developer compete with bigger publishers

Two weeks ago I noticed that the Apify Store had zero security scanners for any of the popular Backend-as-a-Service platforms. Not one. Search for "supabase security" or "firebase security" or "strapi security" and the results were a mix of unrelated scrapers and outdated forks.

The market gap was screaming at me. Every BaaS makes the same architectural promise: "your data is private because we have role-based access control." And every BaaS makes the same operational mistake: most developers leave at least one collection or table readable to anonymous users in production.

Across 100+ projects I've audited:

  • 22% of Supabase projects leak data anonymously (RLS forgotten on at least one table)
  • 23% of Firebase projects have firestore.rules with if true or expired test-mode rules
  • Strapi templates ship with Public-role find enabled — the warning to disable is rarely seen
  • Directus Public-role read on directus_users exposes hashed passwords and tokens
  • PocketBase, Appwrite, Nhost, Payload CMS — same story, different syntax

So I built a scanner for each one. Eight in nine days. All public on Apify. All free to run. Each one converts to a $99 turnkey "I'll fix it for you" service that I do off-platform via Stripe.

Here's the pattern that let me ship that fast.

The single-file scanner template

Every BaaS exposes a public REST endpoint per collection/table. The probe is always the same shape:

async function probe(url, collection) {
  const probeUrl = `${url}/<api-path>/${encodeURIComponent(collection)}?<limit-1-param>`;
  try {
    const r = await fetch(probeUrl, { signal: AbortSignal.timeout(8000) });
    if (r.status === 200) {
      const j = await r.json();
      const total = extractTotal(j);                    // varies per BaaS
      const sampleCols = extractSampleColumns(j);       // varies per BaaS
      return { exists: true, readable: true, total, sampleCols };
    }
    if (r.status === 403 || r.status === 401) return { exists: true, readable: false };
    return { exists: false };
  } catch (e) {
    return { exists: false, error: e.message };
  }
}
Enter fullscreen mode Exit fullscreen mode

The differences per BaaS are surgical:

BaaS API path Limit param Count source
Supabase /rest/v1/{table} Range: 0-0 (header) + Prefer: count=exact Content-Range header
Strapi v4+ /api/{collection} pagination[limit]=1 meta.pagination.total
Strapi v3 /{collection} _limit=1 data.length (no total)
Directus /items/{collection} limit=1&meta=total_count meta.total_count
Payload CMS /api/{collection} limit=1 totalDocs
PocketBase /api/collections/{name}/records perPage=1 totalItems
Nhost (Hasura) POST /v1/graphql _aggregate { count } data.X_aggregate.aggregate.count
Appwrite /v1/databases/{db}/collections/{c}/documents ?limit=1 + X-Appwrite-Project header total
Firebase Firestore /v1/projects/{p}/databases/(default)/documents/{c} pageSize=1 (returns docs directly)

That's it. Same shape, 60-90 minutes to write the next one once the first is done.

The leverage: shared HTML report renderer + CTAs

Each scanner produces JSON dataset rows AND an HTML report saved to the run's key-value store. Same HTML renderer, parameterized per BaaS. Each report ends with:

  1. Severity-color-coded findings table (critical/high/medium/low)
  2. curl reproducer per finding — the exact request an attacker would make
  3. Paste-ready fix code specific to the BaaS (SQL ALTER TABLE ENABLE ROW LEVEL SECURITY, or rules-file diff, or admin-panel click path)
  4. CTAs: turnkey $99 fix offer, $29/mo continuous auto-scans, and the open-source CLI

Every report ends with: "Solo dev competing with bigger publishers — a 30-second review on Apify is the single thing that lifts ranking. Thank you." That last line is what makes reviews actually happen.

The "demo mode" trick that 10x'd conversion

Apify Store visitors hit the actor page, see the input fields, and bounce 80% of the time when they realize they need to paste in their project URL + an anon key just to see what the report looks like.

The fix: remove required from the input schema and add a demo branch at the top of main.js:

if (!supabaseUrl || !anonKey) {
  console.log('🎬 DEMO MODE: No project URL/key provided. Generating sample report.');
  const demoReport = { /* hardcoded plausible findings */ };
  // ... render HTML with a yellow "DEMO" banner up top
  return;
}
Enter fullscreen mode Exit fullscreen mode

Now anyone can hit "Run" with zero input and immediately see what a real scan returns — with full severity table, sample sensitive columns, copy-pasteable fix snippets, and CTAs. The Run button always succeeds and always educates.

This single change made the actor genuinely viral-able. You can paste the actor URL in a Slack/Discord/forum and the recipient gets value in 3 seconds without any commitment.

The 8 actors

Each one is the only scanner of its kind in the Apify DEVELOPER_TOOLS category as of today. That's the whole point — competing on undefended ground.

What's next

I'm building Convex and Xata scanners next. After that I'll likely stop adding new ones and focus on:

  1. One blog post per BaaS showing a real (anonymized) leak I found in the wild
  2. GitHub code-search outreach — F5Bot alerts me when someone commits an anon key in public; I send them the scanner link
  3. A "BaaS leak registry" open-source page indexing known-bad patterns per platform

If you build on any of these BaaS, run the scanner on your own project. The demo mode means you can see the report shape first. Most projects don't leak, but the 22% that do mostly don't know yet.

If you publish to Apify Store yourself: the demo mode pattern is a free 10x to your run-button conversion. Took me too long to figure out — saving the next person that time.


Renzo, solo developer in Lima, Peru. I scan, write, and ship security tools at the intersection of "I should automate this" and "let me publish it as a product." Open source: @perufitlife/supabase-security.

If you found this useful, a follow on dev.to helps a solo developer keep shipping. Or just leave a review on any of the 8 scanners — reviews are the single biggest lever a new Apify publisher has.

Top comments (0)