FixVibe

// docs / baas security / firebase rules scanner

Firebase rules scanner: find open Firestore, Realtime Database, and Storage rules

Firebase apps fail security in one consistent way: <code>allow read, write: if true;</code> rules left over from the test-mode quickstart, never replaced before production. AI coding tools generate these rules verbatim from documentation examples and rarely prompt the developer to harden them. This article shows how a Firebase rules scanner detects open rules across Firestore, Realtime Database, and Cloud Storage from outside the project — and how to fix what it finds.

How the scanner finds open Firebase rules

Firebase services expose well-known, predictable URL shapes. A scanner with no credentials can probe each one and observe whether anonymous reads succeed. The FixVibe <code>baas.firebase-rules</code> check runs in three independent probes — one per Firebase service:

  • <strong>Firestore.</strong> The scanner extracts the project ID from the deployed app's bundle (it's in <code>firebase.initializeApp({ projectId: ... })</code>), then issues <code>GET https://firestore.googleapis.com/v1/projects/[project-id]/databases/(default)/documents/[collection]:listDocuments</code> against common collection names. A <code>200 OK</code> with documents in the response means <code>allow read</code> is permissive.
  • <strong>Realtime Database.</strong> The scanner probes <code>https://[project-id]-default-rtdb.firebaseio.com/.json</code>. If the root is readable anonymously, the response is the entire database tree as JSON. A more conservative test queries <code>.json?shallow=true</code>, which returns top-level keys only — a finding either way.
  • <strong>Cloud Storage.</strong> The scanner queries <code>https://firebasestorage.googleapis.com/v0/b/[project-id].appspot.com/o</code>. If the response lists file names without authentication, the bucket is anon-listable. Listable storage is a finding even when individual file downloads are denied — attackers enumerate the bucket to find guessable filenames.

What the test-mode footgun actually looks like

Firebase's quickstart documentation includes one of the most-copied rule blocks on the internet:

firebase
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}

Firebase used to add an automatic 30-day expiry on these rules. That changed: today the rules persist forever unless the developer replaces them. AI coding tools — having trained on years of documentation that includes the test-mode block — frequently emit it verbatim and tell the developer "this is your security rule." It is not.

Other variants that show up in production but are equally permissive:

firebase
// future-date variant — equivalent to "if true"
allow read, write: if request.time < timestamp.date(2099, 1, 1);

// authenticated-user variant — any signed-in user reads and writes anything
allow read: if true;
allow write: if request.auth != null;

// any-auth variant — any signed-in user owns every document
allow read, write: if request.auth != null;
  • A future-timestamp variant: a rule that allows everything until a date far in the future. Never effectively expires (see the highlighted block above).
  • <code>allow read: if true; allow write: if request.auth != null;</code> — public reads, any authenticated user can write.
  • <code>allow read, write: if request.auth != null;</code> — any signed-in user can read or write any document, including other users' data.

What to do when the scanner finds an open rule

Open Firebase rules are a runtime emergency. The fix is the same shape across all three services: scope every rule to <code>request.auth.uid</code> against an explicit owner field. Each service has its own rule syntax:

Firestore

<code>match /users/'{'userId'}' '{' allow read, write: if request.auth != null && request.auth.uid == userId; '}'</code>. The path-segment binding <code>'{'userId'}'</code> becomes the only document the user can touch.

firebase
match /users/{userId} {
  allow read, write: if request.auth != null
                     && request.auth.uid == userId;
}

Realtime Database

<code>{ "rules": { "users": { "$uid": { ".read": "$uid === auth.uid", ".write": "$uid === auth.uid" } } } }</code>. The <code>$uid</code> wildcard captures the path segment for comparison.

json
{
  "rules": {
    "users": {
      "$uid": {
        ".read":  "$uid === auth.uid",
        ".write": "$uid === auth.uid"
      }
    }
  }
}

Cloud Storage

<code>service firebase.storage '{' match /b/'{'bucket'}'/o '{' match /users/'{'userId'}'/'{'allPaths=**'}' '{' allow read, write: if request.auth.uid == userId; '}' '}' '}'</code>. Convention: store files under <code>users/[uid]/[filename]</code> and let the path enforce ownership.

firebase
service firebase.storage {
  match /b/{bucket}/o {
    match /users/{userId}/{allPaths=**} {
      allow read, write: if request.auth.uid == userId;
    }
  }
}

Deploy rules via the Firebase CLI: <code>firebase deploy --only firestore:rules</code>, <code>firebase deploy --only database</code>, <code>firebase deploy --only storage</code>. Verify the new rules are in production by re-running the FixVibe scan — the <code>baas.firebase-rules</code> finding should clear.

bash
firebase deploy --only firestore:rules
firebase deploy --only database
firebase deploy --only storage

How this compares to Firebase's built-in tools

Firebase Console shows you the current rules but doesn't audit them against runtime behaviour. The Firebase Rules simulator lets you test rule logic against synthetic requests — useful but local. <strong>Neither tool tells you what your production rules actually return to an anonymous attacker on the public internet.</strong> An external scanner like FixVibe (or Burp Suite with manual configuration) is the only thing that probes from the same angle an attacker would. Google's own <em>App Check</em> mitigates abuse but does not substitute for correctly-scoped rules.

Frequently asked questions

Does the scanner read or modify my Firestore data?

Passive scans issue at most one anonymous read per service to confirm whether rules permit it. The scanner records response shape and the presence of data — it does not paginate, does not enumerate documents, and does not write. Write probes are gated behind verified domain ownership and never run against unverified targets.

What if my Firebase project uses App Check?

App Check rejects unauthenticated requests with a <code>403</code>. A scanner without an App Check token will see <code>403</code> on every probe — which is the correct outcome. App Check is not a substitute for rule correctness (a stolen App Check token plus an open rule still leaks data), but it does block opportunistic external scans.

Can the scanner detect partial rule misconfigurations (read open, write closed)?

Yes — each rule (<code>allow read</code>, <code>allow write</code>) is probed separately. A read-only probe that succeeds with a <code>200 OK</code> reports an open-read finding even if writes are denied. The two findings are distinct: data exfiltration and data manipulation are separate risks.

Does this work for Firebase apps deployed under a custom domain?

Yes. The scanner extracts the Firebase project ID from the deployed bundle, not from the domain. Custom domains, app.web.app subdomains, and self-hosted Firebase apps all work the same way as long as the JavaScript bundle is reachable.

Next steps

Run a free FixVibe scan against your production URL — the <code>baas.firebase-rules</code> check ships on every plan and flags open rules across Firestore, Realtime Database, and Cloud Storage. For a deeper explainer on the <code>allow read, write: if true</code> pattern specifically, see <ifTrueArticle>Firebase allow read, write: if true explained</ifTrueArticle>. For the umbrella view across Supabase, Firebase, Clerk, and Auth0, read <baasScannerArticle>BaaS misconfiguration scanner</baasScannerArticle>.

// scan your baas surface

Find the open table before someone else does.

Drop in a production URL. FixVibe enumerates the BaaS providers your app talks to, fingerprints their public endpoints, and reports what an unauthenticated client can read or write. Free, no install, no card.

  • Free tier — 3 scans / month, no signup card.
  • Passive BaaS fingerprinting — no domain verification needed.
  • Supabase, Firebase, Clerk, Auth0, Appwrite, and more.
  • AI fix prompts on every finding — paste back into Cursor / Claude Code.
Run a free BaaS scan

no signup required

Firebase rules scanner: find open Firestore, Realtime Database, and Storage rules — Docs · FixVibe