Firebase quickstarts and "test mode" hand you a database and a storage bucket wide open (.read: true, .write: true) and tell you to come back and lock them down later. A surprising share of shipped apps never do. Both Firebase Realtime Database and Firebase Cloud Storage use declarative security rules that are easy to get wrong in ways that silently expose every user's data to any anonymous caller on the internet. This guide covers how each exposure happens, how to detect it, and how to lock rules down to the right scope.

Firebase Realtime Database: the .read: true trap

Firebase Realtime Database is a JSON document store whose security is governed by a rules file (typically database.rules.json). Rules are evaluated server-side on every request. The most dangerous rule is also the simplest:

{
  "rules": {
    ".read": true,
    ".write": true
  }
}

This is the default rule shipped with many Firebase quickstart guides and tutorials. When deployed, it grants every unauthenticated internet caller the ability to read and write the entire database. No Firebase account is required, not even an anonymous Firebase Auth session.

The .json enumeration trick

Firebase Realtime Database exposes a REST API. The host depends on when and where the database was created. Older or US-region instances use:

https://<project-id>.firebaseio.com/<path>.json

Databases created more recently, or outside the US, use a region-qualified host on a different domain:

https://<db-name>.<region>.firebasedatabase.app/<path>.json

Both forms behave identically, and any path is fetched by appending .json to it. If you only probe firebaseio.com, you miss every instance created on the newer host. With .read: true at the root, a single unauthenticated request dumps the entire database tree:

GET https://<project-id>.firebaseio.com/.json

A 200 response containing a JSON object confirms full anonymous read access. A 401 response indicates authentication is required. The response for a large database can be many megabytes, and the request itself is indistinguishable from a normal app request. RTDB enforces platform-level connection and quota limits, but nothing in the rules language rate-limits an individual path, so there is little to slow a scraper working through an open one.

The auth != null anonymous-auth pitfall

Many developers tighten their rules to:

{
  "rules": {
    ".read": "auth != null"
  }
}

This looks restrictive but has a critical nuance: auth != null means any Firebase Auth user for your project, including users authenticated via Anonymous Authentication. Firebase custom tokens are project-specific and do not grant cross-project access, but anonymous auth is a different matter entirely. If your project has the Anonymous Authentication sign-in provider enabled, any caller can invoke signInAnonymously() against your project's client SDK, receive a valid token scoped to your project, and immediately satisfy auth != null. No real account, no password, and no invitation needed.

So once the Anonymous provider is enabled, "only authenticated users can read" quietly becomes "anyone on the internet can read." And enabling it is common: quickstarts and consumer-app onboarding often turn it on so people can use the app before they create an account.

Firebase Cloud Storage: allow read: if true

Firebase Cloud Storage uses a different rules language, but the same failure mode applies. Storage rules live in a storage.rules file and are evaluated per request. An open-rule example:

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if true;
    }
  }
}

This allows any unauthenticated caller to read and write any file in the bucket. Like the Realtime Database equivalent, it is common in tutorial code and often ships to production unchanged.

The same auth != null pitfall applies to Storage rules. The rule:

allow read: if request.auth != null;

grants read access to any authenticated user in this project, including anonymous sessions. If the Anonymous provider is enabled, a caller can signInAnonymously(), receive a token scoped to your project, and read every file the rule covers. Profile photos, user-uploaded files, and application assets are all in reach of someone who never created a real account.

How to detect open rules

Realtime Database: unauthenticated probe. Without any credentials or Firebase SDK, request the root of the database:

GET https://<project-id>.firebaseio.com/.json

If the response is a JSON payload (even null), the database is readable without authentication. A 401 with {"error":"Permission denied."} means authentication is required.

Realtime Database: Firebase console. Open the Firebase console, navigate to Realtime Database → Rules. If the rules tab shows ".read": true or ".read": "auth != null" at the root and Anonymous Authentication is enabled (Authentication → Sign-in method → Anonymous → Enabled), the database is effectively open to unauthenticated callers.

Storage rules: Firebase emulator. The Firebase Local Emulator Suite includes a rules coverage tool. Run:

firebase emulators:start --only storage

Then issue an unauthenticated request against the emulator's storage endpoint and observe whether it succeeds. The emulator's rules debug output will show exactly which rule matched.

Check a Firebase endpoint here. Paste the firebaseio.com or firebasestorage.googleapis.com URL into the open-bucket viewer to probe anonymously and see what an unauthenticated caller can access.

What's at risk

When a Firebase Realtime Database is open to unauthenticated reads, a single GET request can return every record stored in the application. Mobile apps frequently store:

  • User profiles, including names, email addresses, phone numbers, and home addresses.
  • Session tokens and device push-notification identifiers.
  • Application state data, purchase histories, and message threads.
  • Internal configuration objects, sometimes including third-party API keys hardcoded at database setup time.

Open write rules are the real disaster. An unauthenticated caller who can write to the database root can overwrite or delete application data, inject malicious content, or quietly escalate privileges by flipping a role or isAdmin field directly in the record. The database is the source of truth, and nothing else gets a vote.

Storage exposures leak whatever users uploaded, and in practice that is KYC identity documents more often than anything else. Firebase is the default backend for consumer-fintech MVPs, the kind of app that asks for a passport scan on day one, and those scans land in a bucket the team forgot to lock.

How to lock rules down

Realtime Database: scope reads to individual users.

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

This grants each authenticated user read and write access only to their own subtree (/users/<their-uid>), not to the entire database.

Storage rules: scope to the authenticated user's path.

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;
    }
  }
}

This restricts access to paths under /users/<uid>/ to the authenticated user who owns that path, using exact UID matching rather than a broad auth != null check.

Disable Anonymous Authentication if you don't need it. In the Firebase console, navigate to Authentication → Sign-in method and disable the Anonymous provider if your app does not require it. This closes the auth != null anonymous-auth gap: no one can obtain a valid token without a real credential.

Validate rules before deploying. Use the Firebase Rules Playground in the console (Realtime Database → Rules → Rules Playground) to simulate requests with auth=null before deploying any rule change. The emulator's rules coverage tool provides the same capability for local testing.


For an index of exposed Firebase Realtime Database instances found by this service, see the Firebase Realtime Database exposure index. For Firebase Cloud Storage exposures, see the Firebase Storage exposure index. To test a specific Firebase URL right now, use the open-bucket viewer.