Firebase Rules Are Public
Firebase is built for the browser to talk to the database directly. That's why your Firebase config, including the apiKey, sits in your public JavaScript. It's also why Firebase Security Rules are the only thing between a stranger and your data. If your rules say ".read": true, or you're still running the test-mode rules from the day you started, anyone who finds your database URL can read it.
The Pro Logica AI App Security Check runs a safe, shallow read test against your Firebase Realtime Database. Run the free check.
Why the Firebase config isn't the problem
Firebase's documentation is clear that the API keys in a Firebase web config aren't secret. They identify your project to Google's services. Hiding them doesn't protect anything. What protects your data is the rules your database enforces on every request, together with Firebase Authentication. (It's still smart to restrict the key in Google Cloud Console to your domains and the APIs you use, which protects your billing.)
That's why our scan reports "Firebase configuration in client" as low severity and then goes on to test the part that matters.
What "rules allow all" looks like
Realtime Database rules are JSON. This is the version that makes your whole database world-readable and writable:
{
"rules": {
".read": true,
".write": true
}
}
A close cousin is the test-mode rule set Firebase offers when you create a database. It allows all reads and writes until a timestamp you choose, something like ".read": "now < 1767225600000". Apps often launch while that window is still open, and some get extended "just for now."
Cloud Firestore has the same problem in its own syntax:
match /{document=**} {
allow read, write: if true;
}
How to test safely
From the Firebase console. Open Realtime Database (or Firestore) → Rules and read what's there. Use the Rules Playground to simulate an unauthenticated read of / and of a sensitive path, such as /users. If the simulator allows it, so does the internet.
With the Local Emulator Suite. Write rules unit tests that assert both allowed and denied cases before you deploy rule changes.
From the outside (what our scan does). When we find your Realtime Database URL in your JavaScript, we request /.json?shallow=true once, with no sign-in. shallow=true returns only top-level key names, never the data under them. Here's how we read the result:
- 401/403 or "Permission denied": rules are blocking anonymous reads. That's the safe result.
null: nothing is readable, or the database is empty. Not flagged.- A 200 response with content: your root is publicly readable. We flag it as critical and store only the endpoint and status code, never the data.
This test only runs when you confirm you own the app or have permission. It covers the Realtime Database. The scan doesn't test Firestore or Cloud Storage rules, so check those in the console using the steps above.
How to lock rules down
1. Start from deny-all and open only what you need.
{
"rules": {
".read": false,
".write": false,
"users": {
"$uid": {
".read": "auth != null && auth.uid === $uid",
".write": "auth != null && auth.uid === $uid"
}
},
"publicPosts": {
".read": true,
".write": "auth != null"
}
}
}
Each user can read and write only their own record. A public collection is readable by everyone, and only signed-in users can write to it.
2. For Firestore, use the same idea:
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
3. Validate writes. Use .validate (Realtime Database) or conditions on request.resource.data (Firestore) so a signed-in user can't write junk, or set fields like role: "admin".
4. Remember that authenticated isn't the same as authorized. auth != null lets any signed-in user in, and in many apps anyone can sign up. Scope rules to the owner or to a role stored where users can't edit it.
5. Consider App Check to reduce abuse from scripts that aren't your app. It's an extra layer, not a replacement for rules.
6. Deploy and retest. Publish the rules, rerun the Rules Playground checks, then rescan.
Where Firebase shows up in AI-built apps
Most Lovable and Bolt apps use Supabase, but Firebase is common in apps built with Cursor, Replit and v0, especially when the AI picked "the fastest backend." The pattern is the same as an open Supabase table, so the Supabase RLS guide is worth a read if you use both.
Related
- Supabase RLS not enabled
- Exposed API key in frontend, including when an
AIzakey is fine - By builder: Cursor · Replit · v0 · Lovable · Bolt.new
- Next step: Run the free check on your app · Pro Logica cybersecurity services
FAQ
Is my Firebase API key a secret?
No. Firebase web API keys identify your project and are meant to be in client code. Your Security Rules protect the data. Restrict the key by referrer and API to protect your quota and billing.
What are "firebase security rules for authenticated users"?
They're rules that check auth (Realtime Database) or request.auth (Firestore). Checking only that a user is signed in isn't enough when anyone can sign up. Also check that the user owns the record, using auth.uid.
Will your test download my database?
No. We send one /.json?shallow=true request, which returns top-level key names at most, and we store only the status. It runs only when you confirm ownership.
Do you test Firestore too?
Not in the automated scan. It tests the Realtime Database. Use the Rules Playground in the Firebase console to check Firestore and Storage rules.
Check whether your database is open in about a minute. Run the free AI app security check.
By Pro Logica