Firebase is an incredible platform that lets us build apps faster than ever. But with great power comes great responsibility. One of the most common and dangerous mistakes developers make is leaving their Firebase database wide open, essentially inviting attackers to read, steal, and delete their users' data.

This isn't a theoretical problem. Publicly accessible Firebase instances are actively scanned for by malicious actors. Let's look at how easy it is to exploit this and, more importantly, how to fix it.

The Danger Zone: Default Test Rules

When you create a new Firestore or Realtime Database in "test mode," Firebase applies a set of rules that are only meant for initial development. They look like this:

Default Insecure Rules
{
  "rules": {
    ".read": "true",
    ".write": "true"
  }
}

This literally means anyone on the internet can read and write to your entire database. Firebase warns you that these rules expire in 30 days, but many developers either ignore the warning, extend the date, or simply change "now < ... " to "true" and forget about it.

How an Attacker Reads Your Data

An attacker doesn't need your app or any special tools. All they need is your Firebase Project ID, which is often publicly available in your app's configuration files or network traffic. Once they have it, they can use Firebase's own REST API to access your data.

Imagine you have a users collection. An attacker can dump all of it with a single command:

API Request to Read All User Data
# Replace YOUR-PROJECT-ID with the actual ID
curl "https://YOUR-PROJECT-ID.firebaseio.com/users.json"

If your rules are open, this command will return a JSON object containing every document in your users collection. This could include names, emails, phone numbers, and any other private information you store.

How an Attacker Writes or Deletes Your Data

It gets worse. With write access open, an attacker can modify or completely wipe your data just as easily.

Using the same REST API, they can overwrite a user's data with a PUT request:

API Request to Overwrite Data
# Overwrites the user with ID 'user123'
curl -X PUT -d '{"name": "pwned", "email": "hacked@example.com"}' \
"https://YOUR-PROJECT-ID.firebaseio.com/users/user123.json"

Or they can delete data with a DELETE request:

API Request to Delete an Entire Collection
# This deletes the ENTIRE 'users' collection
curl -X DELETE "https://YOUR-PROJECT-ID.firebaseio.com/users.json"
Think about it: One simple command could wipe out your entire user base. This is why securing your rules is not optional.

Beyond Data Theft: The Hidden Dangers

The impact isn't just limited to reading and writing user data. The real nightmare begins when your backend services trust the data stored in Firebase. If an attacker can write to your database, they can inject malicious payloads that target your own infrastructure.

For example, if your application takes a URL from a Firebase document and displays it in a WebView, an attacker with write access can change that URL to their own phishing site. Your app will then unknowingly serve malicious content to your users, using your app's trusted name.

Example: Injecting a Phishing URL
# Attacker changes the 'terms_of_service_url' in your app's config
curl -X PUT -d '"https://my-evil-phishing-site.com/login"' \
"https://YOUR-PROJECT-ID.firebaseio.com/app_config/terms_of_service_url.json"

Even worse, if a backend process reads a value from Firebase and uses it to make a network request or run a system command, this could lead to Server-Side Request Forgery (SSRF) or even Remote Code Execution (RCE). An attacker could inject an internal IP address to scan your network, or a malicious command to compromise your entire server environment. The possibilities are terrifying.

The Solution: Writing Secure Rules

The fundamental principle of Firebase security is to deny all access by default and then grant it selectively. Never start with allow read, write: if true;.

Step 1: The Bare Minimum (Authenticated Users)

At the very least, you should ensure that only logged-in users can read or write data. This prevents anonymous attacks.

Good: Allow Access Only to Logged-in Users
{
  "rules": {
    "rules": {
      "match /{document=**}": {
        "allow read, write": "if request.auth != null"
      }
    }
  }
}

This is much better, but it still means any logged-in user can read and write any other user's data. We need to be more specific.

Step 2: The Right Way (Owner-Only Access)

The best practice for user data is to ensure that users can only access their own information. You can achieve this by structuring your database around user IDs (UIDs) and using those UIDs in your rules.

If your data is structured like /users/{userId}/..., you can write this powerful rule:

Best: Allow Users to Access Only Their Own Data
{
  "rules": {
    "rules": {
      "users": {
        // The {userId} wildcard matches any document in the 'users' collection
        "match /{userId}": {
          // A user can read or write to their own document if their UID matches the document's ID
          "allow read, write": "if request.auth.uid == userId"
        }
      }
    }
  }
}

With this rule in place, the malicious curl commands we saw earlier would all fail with a "Permission Denied" error. You've successfully locked the door.

Securing your Firebase database is one of the most important steps you can take. Don't wait until it's too late. Go check your rules right now!