All guides
Critical severityDatabase Security

Firebase Security Rules: stop leaving your database open

Firebase web apps read and write Firestore, Realtime Database and Cloud Storage directly from the browser, using a config object that anyone can see. Security Rules are the only thing that decides whether a request is allowed. Rules left in test mode, or loosened to allow everything, expose your entire database to the internet.

What it is

Security Rules are a small policy language evaluated on Google's servers for every read and write. Each match block targets a path — a collection, a document, a storage folder — and allow statements say which operations are permitted under which conditions, using request.auth (who is asking) and request.resource.data (what they are trying to write).

The Firebase web config, including its apiKey, only identifies your project; it is not a secret and doesn't grant access on its own. That's why rules matter so much: any visitor can initialize the Firebase SDK with your config and query your database directly from their own browser console.

Why it matters

Firestore's test mode allows all reads and writes until an expiry date. When the deadline hits and the app breaks, a common "fix" is allow read, write: if true — which leaves every document world-readable and writable. Exposed Firebase databases are a recurring source of large data leaks, and they are trivial to find and dump.

Rules that only check request.auth != null aren't much better: anyone can create an account, often anonymously, and then read every user's data. Without validating writes, users can also edit fields they should never control — for example setting role: "admin" on their own profile.

How to fix it

Replace open rules with owner-based rules

Deny by default and grant access per collection. Here each user can only read and write their own document in users, and nothing else is reachable.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write: if request.auth != null
        && request.auth.uid == userId;
    }
    // Every other path is denied by default.
  }
}
Validate what users are allowed to write

Restrict which fields a user may change so they can't promote themselves or tamper with server-managed data. affectedKeys().hasOnly() rejects any update that touches other fields.

match /users/{userId} {
  allow update: if request.auth.uid == userId
    && request.resource.data.diff(resource.data)
         .affectedKeys().hasOnly(["displayName", "photoURL"]);
}
Remove recursive wildcards and test-mode rules

Search your rules for match /{document=**} combined with a broad allow, for if true, and for expiring test-mode timestamps. Remember that Cloud Storage and Realtime Database have separate rules files — lock those down too.

Test your rules like an attacker

Use the Rules Playground in the Firebase console or the Emulator Suite with @firebase/rules-unit-testing to run reads as an unauthenticated user and as a different signed-in user. A quick external check is an unauthenticated REST request — if it returns documents, the collection is public.

curl "https://firestore.googleapis.com/v1/projects/<project-id>/databases/(default)/documents/users"

FAQ

Is my Firebase apiKey a secret?

No. The apiKey in the Firebase web config identifies your project and is meant to ship to the browser. Protect your data with Security Rules, and restrict the key in Google Cloud to the APIs your app actually uses so it can't be reused for other billable Google services.

Is request.auth != null enough?

Rarely. It only proves the requester is signed in — not that the data belongs to them. Compare request.auth.uid to the document owner, or check a role that users can't set themselves.

Does AppSafe check my Firebase rules?

AppSafe doesn't query your Firebase project, so it can't evaluate your rules — use the Rules Playground or the curl check above. It does flag Google API keys (the AIza… format) found in your JavaScript, because the same format is used for billable services like Maps or Gemini. For a Firebase web config that's expected; just make sure the key is restricted.

Is your app affected?

AppSafe checks for this and dozens of other issues in one free scan.

Scan my app free