Skip to content

Are My Firebase Security Rules Leaving My Database Open to the Public?

6 min read

If you built your app on Firebase and never touched the security rules, the honest answer is probably yes: your database is open to the public. Firebase starts new projects in test mode, which lets anyone on the internet read and write your entire database, and that mode is supposed to last 30 days. Many vibe-coded apps ship it to real users anyway.

What security rules are, and why yours are open

Firebase security rules are the lock on your database. They sit on the server and decide, for every single read and write, whether that request is allowed. Your app's login screen does not protect anything, because an attacker never uses your app. They call the Firebase API directly with your public config, which ships in the browser and is meant to be public.

When you create a Firestore or Realtime Database, Firebase offers test mode to get you moving, with a rule that effectively says "allow everyone." The agent building your app used it because it works instantly and nothing gets in the way of the demo. Nobody asked whether the database should be world-readable, so it was left world-readable. The agent built what you asked for and not the part you didn't know to ask for.

How to check

  1. Open the Firebase console, pick your project, and go to Firestore Database (or Realtime Database), then the Rules tab.

  2. Look for either of these, which both mean fully open:

    // Firestore, test mode
    allow read, write: if true;
    
    // or a time-bomb that has usually already expired
    allow read, write: if request.time < timestamp.date(2025, 1, 1);
    
    // Realtime Database, open
    { "rules": { ".read": true, ".write": true } }
    
  3. Prove it from the outside. With your public project ID you can hit the REST endpoint of a collection:

    curl "https://firestore.googleapis.com/v1/projects/YOUR_PROJECT_ID/databases/(default)/documents/YOUR_COLLECTION"
    

    If documents come back with no auth, anyone on the internet can read that data.

The fix

  1. Deny by default. Start from a rule that allows nothing, then open exactly what the app needs. In Firestore:

    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
        match /{document=**} {
          allow read, write: if false;
        }
      }
    }
    
  2. Scope each collection to its owner. For per-user data, require a signed-in user and match the document to them:

    match /profiles/{userId} {
      allow read, write: if request.auth != null
                         && request.auth.uid == userId;
    }
    
  3. Validate writes, don't just gate them. Check field types and that a user cannot set userId to someone else, so nobody can write junk or claim another person's records.

  4. Publish, then re-test. Click Publish, re-run the curl above signed out (it should now be denied), then test in the app as a real user and confirm they see only their own data.

  5. Do the same for Storage rules. Firebase Storage has its own separate rules that also default open in test mode. Uploaded files are a leak too.

The trap to avoid

Do not just push the expiry date further into the future. A rule like if request.time < timestamp.date(2027, 1, 1) is still "allow everyone," only for longer. The date is not a lock. Real rules check who is making the request and what they are touching, not what day it is.

Where this fits

An open Firebase database is one of the first things a stranger finds, and it never shows up in a demo because everything works when the rules are wide open. It is the Firebase version of the same gap Supabase apps have with Row Level Security, and it sits right next to the anon key that is meant to be public. Even with rules in place, check that a user cannot change the ID in a request to reach data that isn't theirs. The free Readiness Report runs these checks against your real project and tells you which collections are exposed before your first users arrive; the Finishing Pass hands you the fixes in order.