Skip to content
All guides

Firebase security rules open to everyone: how to fix 'allow read, write: if true'

By Obscura Security · Updated · Firebase, Firestore, Cloud Storage, Realtime Database

Short answer

Rules like 'allow read, write: if true' mean anyone on the internet can read, change and delete your data, because your Firebase config is public by design. Replace them with rules that check request.auth.uid, and test them in the Rules Playground before you publish.

If your Firebase rules contain if true, or you started in “test mode” and never changed them, your database may be readable and writable by anyone who knows your project ID.

Why this happens

Firebase web apps talk to Firestore, Realtime Database and Cloud Storage directly from the browser. The config object in your frontend (apiKey, projectId and so on) is public, and Firebase says that’s fine. The only thing standing between a stranger and your data is your security rules.

Two things lead to open rules:

  • Test mode. When you create a database in test mode, Firestore starts with a rule like allow read, write: if request.time < timestamp.date(...), open to everyone until the date passes. When the date passes, the app starts failing, and the quick fix people (and AI tools) reach for is to extend the date or write if true.
  • Rules written to make an error disappear. “Missing or insufficient permissions” is the error you see when rules block something. Changing the rule to if true makes it vanish.

How to check your own app

  1. In the Firebase console, open Firestore Database → Rules, and read what is published. Do the same for Realtime Database → Rules and Storage → Rules. Look for if true, a future date in request.time <, or ".read": true and ".write": true.
  2. Use the Rules Playground (a tab in the Firestore and Storage rules editor) to simulate an unauthenticated read and write on a real path. If it says “Allowed”, the rule is open.
  3. From outside, for your own project, try the Firestore REST API with no login:
curl "https://firestore.googleapis.com/v1/projects/YOUR_PROJECT_ID/databases/(default)/documents/users"

A locked database returns a PERMISSION_DENIED error. A list of documents means it’s open.

For Realtime Database, open https://YOUR_DATABASE_URL/.json in a browser (the URL is shown at the top of the Data tab). “Permission denied” is what you want to see.

Only test projects you own.

The fix

The pattern is the same for every product: deny by default, then allow only what a signed-in user needs, based on request.auth.uid.

Firestore

If each user’s data sits in a document keyed by their ID, and other documents store an owner’s ID in a userId field:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    // /users/{uid}: each person can only read and write their own profile
    match /users/{userId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }

    // /orders/{id} with a userId field
    match /orders/{orderId} {
      allow read: if request.auth != null
                  && resource.data.userId == request.auth.uid;

      allow create: if request.auth != null
                    && request.resource.data.userId == request.auth.uid;

      allow update: if request.auth != null
                    && resource.data.userId == request.auth.uid
                    && request.resource.data.userId == resource.data.userId;

      allow delete: if request.auth != null
                    && resource.data.userId == request.auth.uid;
    }
  }
}

Anything not matched by a match block is denied. The extra line on update stops a user changing userId to give a document to someone else.

For genuinely public data, such as published blog posts, allow reads only:

match /posts/{postId} {
  allow read: if resource.data.published == true;
  allow write: if false;
}

Realtime Database

{
  "rules": {
    "users": {
      "$uid": {
        ".read": "auth != null && auth.uid === $uid",
        ".write": "auth != null && auth.uid === $uid"
      }
    }
  }
}

Be careful with .read or .write set on a parent path. Rules in Realtime Database cascade downward, so a permissive rule high up can’t be taken back lower down.

Cloud Storage

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

Upload files to users/<uid>/... and only that user can reach them. For public images, such as product photos, add a separate allow read: if true; on that one folder and leave writes closed.

Test, then publish

Paste the rules into the editor, run signed-in and signed-out requests in the Rules Playground, then publish. Check your app still works for a normal user, and that a second test account can’t see the first one’s data.

Mistakes to avoid

  • Leaving test mode on “for now”. The date passes and the problem comes back in a different form.
  • Using request.auth != null as the only check. Anyone can create an account.
  • Trusting data the client sends. If a rule says request.resource.data.role == 'admin', the user simply sends role: 'admin'. Store roles somewhere users can’t write.
  • Assuming queries are filtered by rules. Firestore rules aren’t filters. A query must be written so that it can only return documents the rules allow, or the whole query fails.
  • Forgetting Storage. Firestore can be locked down while the Storage rules next door still say if true.

Common questions

Is it a problem that my Firebase apiKey is in my frontend code?
No. The Firebase web config is meant to be public. It only identifies your project. What protects your data is your security rules, which is why open rules are the real problem.
My test mode rules expired and the app broke. Can I just extend the date?
That keeps your database open to everyone for another 30 days or so. Write real rules based on who the user is, then publish them.
Is 'allow read, write: if request.auth != null' safe?
It's better than 'if true', but it lets any logged-in user read and write everything. Anyone can sign up, so it is only slightly better. Rules should also check that the data belongs to the signed-in user.
Do security rules apply to my server code?
No. The Firebase Admin SDK, used in Cloud Functions or your own backend, bypasses security rules. That's why server code must do its own access checks.

Written by Obscura Security, an Australian practice that checks web apps for problems like this one. If you want a second pair of eyes on yours, email [email protected].