The AI coding tool that built your Firebase app almost certainly deployed it with open Security Rules. In our scanner data, allow read, write: if true shows up in roughly 40% of Firebase projects that were scaffolded by Cursor, Bolt, Lovable, or Replit. That rule lets anyone on the internet read and overwrite every document in your database with no login required.
That's the single biggest pre-launch risk. But it's not the only one. This guide covers all six things you need to check before your app goes live.
TL;DR
Open Firestore Security Rules are the #1 Firebase launch risk. Fix those first, then audit your env vars for secrets with VITE_/REACT_APP_ prefixes, move service account credentials server-side, and scan your deployed URL before sending traffic. The web apiKey is public by design and doesn't need rotation.
Step 1: Audit your Security Rules for open access {#step-1}
Open the Firebase Console, go to Firestore Database > Rules and check for this pattern:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
If you see if true, your entire database is public. Deploy locked rules immediately:
firebase deploy --only firestore:rules
Check Realtime Database and Cloud Storage rules too. AI tools often leave all three open.
allow read, write: if true means anyone who finds your Firebase project ID can read and delete all your user data. This gets found by automated scanners within hours of launch, not days.
Step 2: Fix environment variable prefixes {#step-2}
Prefixes like VITE_, REACT_APP_, and NEXT_PUBLIC_ tell your bundler to compile that variable into the JavaScript file that ships to every browser. They're fine for public config like your Firebase project ID. They're dangerous for Admin SDK credentials.
Run this check in your project root:
grep -r "VITE_FIREBASE_ADMIN\|REACT_APP_FIREBASE_ADMIN\|NEXT_PUBLIC_FIREBASE_ADMIN\|VITE_GOOGLE_APPLICATION\|REACT_APP_GOOGLE_APPLICATION" . --include="*.env*"
Any hits need to be renamed and moved to server-only variables. If the key has already been deployed with a public prefix, rotate it (see Step 3).
Safe (public Firebase config, fine to prefix):
VITE_FIREBASE_API_KEY=AIzaSy... # public by design
VITE_FIREBASE_PROJECT_ID=my-app-prod
Dangerous (must NOT have public prefix):
FIREBASE_ADMIN_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----..."
FIREBASE_ADMIN_CLIENT_EMAIL=firebase-adminsdk@my-app.iam.gserviceaccount.com
GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
Step 3: Move service account credentials server-side {#step-3}
Your service account JSON file (the one you downloaded from Firebase Console with a private_key field) should never appear in client code. If your app runs firebase-admin anywhere that Vite or webpack might bundle it, move those calls to a server-only path.
For Next.js, put Admin SDK initialization in app/api/ routes or lib/ files that are imported only from API routes. For Vite apps, proxy calls through a backend (Express, Netlify Functions, Cloud Functions).
Check your service account isn't committed to git:
git log --all --full-history -- "*service-account*" "*serviceAccount*" "*.json"
If you get output, the credentials are in your git history. Rotate the key in Firebase Console (IAM & Admin > Service Accounts), then remove the file from git history.
Rotating the service account key isn't enough if it's still in git history. Anyone who cloned or forked your repo still has the old key. Remove it from history AND revoke it in the Firebase Console.
Step 4: Write scoped Security Rules {#step-4}
Replace open rules with rules that actually check who's asking. The minimal pattern for user-owned data:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
match /posts/{postId} {
allow read: if resource.data.published == true;
allow write: if request.auth != null
&& request.auth.uid == resource.data.authorId;
}
}
}
Test in the Firebase Emulator before deploying:
firebase emulators:start --only firestore
Then run your security rules test suite against it. Never push untested rules to production.
Step 5: Enable Firebase App Check {#step-5}
App Check adds a layer between your app and Firebase backends: it verifies that requests come from your actual client, not a bot reusing your public Firebase config.
For web apps, register with reCAPTCHA v3:
- Firebase Console > App Check > Get started
- Register your web app with reCAPTCHA v3 (you'll need a reCAPTCHA site key from Google)
- In your Firebase initialization:
import { initializeApp } from 'firebase/app';
import { initializeAppCheck, ReCaptchaV3Provider } from 'firebase/app-check';
const app = initializeApp(firebaseConfig);
initializeAppCheck(app, {
provider: new ReCaptchaV3Provider('YOUR_RECAPTCHA_SITE_KEY'),
isTokenAutoRefreshEnabled: true,
});
- In Firebase Console, enable App Check enforcement for Firestore and Storage after testing in debug mode
App Check doesn't replace Security Rules. Authenticated users who have a valid token can still abuse your rules if they're too permissive. It's an extra barrier against unauthenticated abuse.
Step 6: Scan before going live {#step-6}
Before sending real traffic, run an external scan on your deployed URL. A scanner checks for misconfigured headers, exposed config, and open CORS policies that you might miss by looking at the source code alone.
CheckYourVibe scans your live URL and flags open Firebase rules, exposed API keys in JavaScript bundles, and missing security headers in one pass.
Run the scan, review the findings, and fix anything critical before announcing your launch.
Run a fresh scan after every significant deploy, not just at initial launch. Security rules can be accidentally reverted during a firebase deploy if you're not tracking your firestore.rules file in version control.
What are the most common Firebase security mistakes at launch?
Open Security Rules (allow read, write: if true), service account JSON keys committed to git, and secrets prefixed with VITE_ or REACT_APP_ that end up in the client bundle. CheckYourVibe finds at least one of these in roughly 40% of Firebase apps scanned.
Is the Firebase web apiKey a secret I need to protect?
No. The web apiKey is designed to be public. It just identifies your project. The real secrets are your service account JSON private key and any Admin SDK credentials. Rotate those if they leak; the web apiKey alone doesn't give anyone write access.
How do I fix 'allow read, write: if true' in Firestore?
Replace it with user-scoped rules: allow read, write: if request.auth != null && request.auth.uid == resource.data.userId. Deploy with firebase deploy --only firestore:rules and test in the Firebase Emulator first.
Can I use firebase-admin in a Vite or Next.js client component?
No. firebase-admin is Node.js-only and must run in a server environment (Cloud Function, API route, or server action). Importing it in client code will either fail at build time or expose your service account credentials in the browser.
What does Firebase App Check actually do?
App Check verifies that requests to your Firebase backend come from your actual app (not a bot, a scraper, or someone using your config to hit your Firestore directly). It's not a substitute for Security Rules, but it reduces automated abuse.
Run a free CheckYourVibe scan before your Firebase app goes live. We check for open Security Rules, exposed credentials, and missing headers in one pass.