Firebase security rules misconfiguration in vibe-coded apps
Your Firebase API key showing up in devtools is expected. A database rule that grants access to anyone who asks is how that public key turns into a full data breach.
Your Firebase apiKey, projectId, and appId appearing in your JS bundle or view-source. This is public client config by design — Google's own documentation confirms it isn't a secret.
A security rule of .read: true / .write: true, or a Firestore rule that never checks request.auth. That is what lets anyone with your public config read or write your entire database.
Why AI-built Firebase apps ship this way
Cursor, Bolt, Lovable, and v0 all make wiring a frontend directly to Firebase fast — that's the appeal. Getting a working prototype often means starting in test mode, where Firebase's own default rules allow open read/write for a limited window so nothing blocks development. The step that gets skipped is going back before launch to write real rules keyed to authenticated users. The app works fine for the person building it, because they're testing with their own account — it looks secure until someone else's browser, using nothing but the public config already in your bundle, sends a request the rules were never written to block.
How to check your rules
In the Firebase console, open Firestore Database (or Realtime Database) → Rules and read exactly what each rule evaluates to for an unauthenticated request. The only fully reliable test is functional, not visual: initialize a Firebase client with just the public config from your bundle, with no sign-in, and attempt to read a collection you expect to be protected.
The fix
Require authentication and scope access to the requesting user explicitly:
// Firestore rules — deny by default, allow only the owner
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /profiles/{userId} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
}
}Write an explicit rule per collection you actually intend to expose, and treat any collection with no matching rule as intentionally denied — Firebase's default when nothing matches is to deny, which is the safe failure mode.
Not sure if your rules actually hold up?
StackSecured tests your live Firebase project with real unauthenticated requests — not just a rules-file review — and tells you exactly which collections are exposed.
Run a free scanCommon questions
Is it safe for my Firebase API key to be visible in my app?
+
Yes. Firebase's client config — apiKey, projectId, appId, and the rest — is designed to be public. It identifies your project to Firebase, the same way a URL identifies a server. It is not the same thing as an Admin SDK service account key, which is a real secret and should never appear in client-side code.
So what's actually dangerous?
+
Your Firestore or Realtime Database security rules. Because the client config is public by design, anyone can initialize a Firebase client against your project using nothing but information already in your JavaScript bundle. What stops that client from reading or writing your data is entirely down to the rules attached to your database — not the key.
How many apps actually have this problem?
+
Security researchers who have audited Firebase-backed apps at scale have repeatedly found tens of thousands of Android and web apps with permissive or default-open database rules exposing user data. It is one of the most consistently reported misconfiguration classes in Firebase-backed apps specifically, precisely because the rules step is easy to skip during a fast build.
Does this apply the same way to Firestore and the Realtime Database?
+
The underlying mistake is the same — a rule that grants read or write access without checking who is asking — but the syntax differs. Realtime Database rules use a JSON-like tree with .read/.write; Firestore uses a separate rules language with match/allow statements. Both default to fully closed if you never write a rule, and both become fully open if you write one that evaluates to true unconditionally.
More reading: Exposed source maps in production · Vibe-coding security statistics 2026 · Supabase RLS: the same mistake, different backend