Firebase Security Rules: Why AI-Built Apps Keep Shipping With Test Mode Enabled
Firebase Security Rules default to test mode—open to the world. Learn why AI-built apps keep shipping insecure and the complete audit checklist to fix it.
Firebase Security Rules are the primary authorization layer for Firestore, Realtime Database, and Firebase Storage—and they default to test mode, which means any authenticated or unauthenticated user can read and write any data in your database for the first 30 days after project creation. That default exists for developer convenience. It becomes a production breach when an AI coding tool builds the entire backend, the developer deploys the app, and the test-mode rules ship to production because nothing in the build pipeline required them to be changed.
The pattern is structurally identical to the Supabase RLS problem: the backend ships with a default configuration that is safe for local development and dangerous in production. With Supabase, the gap is Row Level Security disabled on migration-created tables. With Firebase, the gap is Security Rules left in test mode or written to check authentication without checking data ownership. Both patterns show up in the same kind of app—built fast with an AI coding tool, functional by every metric except security—and both are exploitable with nothing more than the public client configuration.
This post covers what Firebase Security Rules actually do, why AI-built apps consistently ship them insecure, how to audit an existing deployment across Firestore, Realtime Database, and Storage, and how to write rules that enforce real tenant isolation. If your app uses Supabase instead of Firebase, the parallel post on Supabase RLS security in AI-built apps covers the same pattern for the PostgreSQL-backed stack. For the broader attack surface across all vibe-coded apps, our post on vibe-coding security risks for enterprise teams is the starting point.
What Are Firebase Security Rules and Why Do They Matter?
Firebase Security Rules are expressions evaluated server-side by the Firebase backend before any read or write operation completes. They sit between the Firebase client SDK—which runs in the browser or mobile app—and the actual data in Firestore, Realtime Database, or Firebase Storage. Every read, write, create, update, and delete must match a rule that evaluates to true; if no matching rule exists, the operation is denied. Rules are the only authorization layer available to Firebase-backed apps that call the Firebase client SDK directly, because the client SDK does not pass through a server you control.
- →Firestore Security Rules: applied to each collection and document path in Cloud Firestore. Rules can inspect the authenticated user's identity, the document's existing data, the incoming write data, and resource metadata to determine whether an operation is allowed.
- →Realtime Database Rules: a JSON-based rule format applied to paths in the Realtime Database. Older and less expressive than Firestore rules, but still critical—a Realtime Database without rules is fully readable and writable by anyone with the database URL.
- →Firebase Storage Security Rules: applied to files stored in Cloud Storage for Firebase. Many apps lock down Firestore correctly but leave Storage rules open, exposing uploaded files—documents, profile photos, attachments—to anyone who knows the storage bucket URL.
- →App Check: a separate control that restricts which client applications can call your Firebase backend. It is a complement to Security Rules, not a replacement—Rules control what data a client can access; App Check controls which apps can call Firebase at all.
The critical difference from a backend API approach: in a traditional app, your server-side API enforces authorization, and the client never touches the database directly. In a Firebase app using the client SDK, your client JavaScript runs queries directly against Firestore. Your Security Rules are the entire server-side authorization layer. There is no implicit protection from the architecture—anyone can use the Firebase JavaScript SDK with your project configuration to query your database, subject only to what your rules allow.
The Test-Mode Trap: Why AI-Built Apps Ship With Insecure Firebase Rules
When you create a new Firebase project and enable Firestore or Realtime Database, the Firebase console asks you to choose a starting mode: production mode (deny-all) or test mode (allow-all for 30 days). AI coding tools that scaffold Firebase projects—Firebase Studio, Bolt, Cursor, v0—typically select test mode to ensure the generated code works immediately without requiring the developer to write rules during development. The generated app works. The generated app ships. The test-mode rules ship with it.
The 30-day expiry is a deliberate safeguard: Firebase designed test mode to be temporary, not permanent. But when the expiry date passes and the app stops working, developers frequently ask an AI tool to fix the permission denied errors. The tool generates rules like allow read, write: if true—permanently open—or allow read, write: if request.auth != null—which allows any signed-in user to read and write any document regardless of ownership. Both responses resolve the immediate error. Both break production security.
- →Test-mode rules marker: rules containing allow read, write: if request.time < timestamp.date(YEAR, MONTH, DAY); are test-mode rules. Any rule with if true as its condition is permanently permissive. Both patterns must be treated as critical findings in a production deployment.
- →Overly broad authentication checks: allow read, write: if request.auth != null; checks that the user is logged in but does not check what data they are allowed to access. Any authenticated user—including newly registered accounts—can read and write every document in the collection.
- →AI-generated rules with expired timestamps: some AI tools generate test-mode rules with expiry dates already in the past, resulting in deny-all access immediately. Developers remove the condition entirely rather than writing a correct ownership check.
- →Mismatched Firestore and Storage rules: a common pattern in AI-built apps is secure Firestore rules alongside open Storage rules. Firestore was tested, the rules were fixed; Storage was never tested and remains fully open.
Writing Firestore Security Rules That Enforce Tenant Isolation
A correctly written Firestore Security Rule checks two things: whether the user is authenticated, and whether the data being accessed belongs to that user or their organization. Authentication alone—if request.auth != null—is not authorization. The difference between an app that checks authentication and an app that checks authorization is the difference between requiring a user to log in and ensuring that user can only access their own data. In a multi-user app, every query that touches user-specific data needs an ownership check.
- →User-owned documents (most common): for a collection where each document belongs to a single user, use match /users/{userId}/data/{document=**} with allow read, write: if request.auth.uid == userId; The path variable {userId} is matched against the authenticated user UID—only the document owner can read or write it.
- →Organization-scoped collections (multi-tenant SaaS): store the organization ID on each document and verify it against the requesting user's profile: allow read: if request.auth != null && resource.data.orgId == get(/databases/$(database)/documents/users/$(request.auth.uid)).data.orgId; This enforces that users can only read documents belonging to their own organization.
- →Public read, owner write: for content that should be publicly readable but writable only by its creator, combine allow read: if true; with allow write: if request.auth != null && request.auth.uid == resource.data.authorId; This is the correct pattern for listings, public profiles, and published content.
- →Validated writes: use request.resource.data to validate incoming write data and prevent ownership spoofing. For example, allow create: if request.resource.data.userId == request.auth.uid; prevents a user from creating documents with another user's ID as the owner field.
Realtime Database and Firebase Storage: The Rules You Forgot
Firestore and Realtime Database are separate products with separate rules. If your app started with Realtime Database and later added Firestore, the old Realtime Database rules may still be in place—and the old database may still hold live data. Firebase Storage rules are also separate, using a syntax nearly identical to Firestore rules but applied to storage paths. Every Firebase project that uses Storage needs explicit Storage rules; Firestore rules do not cover uploaded files.
- →Realtime Database default rules: the JSON format uses .read and .write keys. A rule of .read: true means the entire database subtree is readable by anyone with the database URL—no authentication required. Check the Realtime Database tab in the Firebase console for any rule containing true without an auth condition.
- →The Realtime Database URL is public: the Realtime Database URL is embedded in your Firebase configuration object, which ships in your client bundle. Without correct rules, a direct GET request to that URL returns all data in JSON format—no authentication, no credentials, just the URL.
- →Storage rules path matching: Firebase Storage rules use match /b/{bucket}/o/{allPaths=**} as the catch-all path. A rule of allow read, write: if true; at this level means every file in your storage bucket is fully public. Any file URL—from profile photos to submitted invoices—is readable by anyone who knows or guesses the path.
- →Cross-product attack surface: an app that locks down Firestore correctly but leaves Storage open allows reading every file your users have uploaded. These files are accessed via storage download URLs that are not protected by Firestore rules and do not require a signed-in session to retrieve.
The Complete Firebase Security Rules Audit
Auditing Firebase Security Rules requires checking every service—Firestore, Realtime Database, and Storage—and testing both allowed and denied cases. The Firebase Rules Simulator in the console is useful for individual path tests; the @firebase/rules-unit-testing library enables automated coverage of your rules in a CI pipeline. For a deployed app where you need to verify the live authorization posture, our security audit service for vibe-coded applications includes a manual Firebase rules review: we test authorization as an anonymous caller, as a signed-in user reading another user's data, and as a user attempting to write to paths they should not own.
- →Step 1 — Read your current rules: in the Firebase console, open Firestore Database, then Rules. Repeat for Realtime Database and Storage. Copy all three to a text editor for side-by-side review before making any changes.
- →Step 2 — Check for test-mode markers: search for if true, if request.time <, and allow read, write: if true. Any of these in production rules is a critical finding. Also check for any expiry timestamp that has already passed—those rules currently deny all access, which means your app is broken in ways developers often fix by opening the rules further.
- →Step 3 — Test as an unauthenticated caller: using curl or the Firebase REST API (https://YOUR-PROJECT.firebaseio.com/.json for Realtime Database), attempt to read data without any Authorization header. If you receive data, your Realtime Database rules are open. For Firestore, use the Firestore REST API with no credentials.
- →Step 4 — Test cross-user access: log in as user A, record a document path that belongs to user A. Then log in as user B and attempt to read and write that document path using the Firebase client SDK in a browser console. If user B can access user A's data, your ownership checks are missing.
- →Step 5 — Audit Storage independently: attempt to list and download objects in your storage bucket using only the file download URL with no credentials. Check storage rules explicitly for allow read: if true at any path level.
- →Step 6 — Check for Admin SDK misuse in client code: search your source for firebase-admin imports and service account credential objects. The Firebase Admin SDK is server-only; any import in client-side JavaScript bypasses all Security Rules and is a critical finding requiring immediate removal.
Running DeployReady as Your Automated Security Baseline
Before a manual Firebase security review, running DeployReady gives you an automated baseline that catches what static analysis can find: exposed API keys in committed environment files, missing security headers, configuration patterns indicating open database rules, and exposed service account credentials. DeployReady is free, MIT-licensed, and runs entirely locally—a single npx deployready command returns a 0-100 readiness score and a prioritized findings list.
DeployReady catches what automation can catch. What it cannot do is verify that your Firebase Security Rules enforce the intended authorization model for your specific data schema. A rule that checks request.auth != null will not trigger a scanner alert—it looks like authorization. Testing whether that rule actually prevents user A from reading user B's data requires an engineer who understands your data model and can construct the specific queries an attacker would use.
Frequently Asked Questions
Are Firebase apps secure by default?
No. Firebase projects created with test mode enabled start with Security Rules that allow any read or write for 30 days, then expire to deny-all. Projects created in production mode start with deny-all rules, which are safe but break any app that queries Firestore or Storage without matching rules. In both cases, the developer must write Security Rules that enforce the correct authorization model before the app is safe for real users. AI coding tools that scaffold Firebase projects frequently select test mode for development convenience, and the resulting rules often ship unchanged to production.
How do I check if my Firebase Security Rules are in test mode?
Open the Firebase console and navigate to Firestore Database, then Rules. Look for any rule containing allow read, write: if request.time < timestamp.date(...); — this is the test-mode pattern with an expiry date. Also look for allow read, write: if true; which is permanently open. For Realtime Database, check for .read: true or .write: true at the root level. If you find any of these patterns in a production project, replace them with rules that check request.auth.uid against the document's owner field before the next deployment.
What is the difference between Firestore Security Rules and Realtime Database Rules?
Firestore Security Rules and Realtime Database Rules are two separate systems with separate consoles, separate rule languages, and separate deployment pipelines. Firestore uses a custom rule language that supports complex expressions, document field access, cross-document reads with get(), and function definitions. Realtime Database uses a simpler JSON-based format with .read, .write, and .validate keys. If your project uses both services—common in apps that started on Realtime Database and later added Firestore—you need rules configured and audited for each service independently.
Does enabling App Check replace Firebase Security Rules?
No. App Check and Security Rules are complementary controls that operate at different layers. App Check verifies that requests come from a legitimate client application—your iOS app, Android app, or web app with a valid attestation—making it significantly harder for automated scripts to abuse your Firebase backend. Security Rules control what data an authenticated client can access once the request reaches Firebase. Both are needed: App Check without correct Security Rules still allows a legitimate app to read any data; correct Security Rules without App Check still allow unauthorized tools to attempt requests.
Is the Firebase API key a secret that needs to be protected?
No. The Firebase API key in your client configuration is a public project identifier, not a credential. It is safe to include in client-side JavaScript and is visible to every user who visits your app. It must be treated as public information. Security for your data comes entirely from your Security Rules, not from keeping the API key hidden. Any attacker can use your public API key with the Firebase JavaScript SDK to call your project; your Security Rules determine what they can and cannot access. This is why correct Security Rules are the only meaningful data access control for Firebase apps—the API key provides no barrier.
How Belsoft Helps Teams Harden Firebase Security
For teams that built with Firebase Studio, Bolt, Cursor, v0, or another AI coding tool and need to harden their app before onboarding enterprise customers, Belsoft runs a focused security audit for vibe-coded applications that covers the full Firebase surface: Firestore rules reviewed against the actual data model and tested for cross-user access, Realtime Database and Storage rules audited independently, Admin SDK usage checked across client bundles, and App Check deployment reviewed. We start with DeployReady to surface the automated findings in minutes, then go further with manual testing that exercises the actual authorization logic under real attack conditions.
The output is a ranked findings report with specific remediation rules for each finding—ready to deploy, not just described—a retest to confirm fixes before you present the results to customers or a security questionnaire, and documentation your team uses to maintain the posture as the data model evolves. If you are preparing for SOC 2 readiness, an enterprise customer's procurement review, or you simply shipped fast and want to know what is exposed, this is the right starting point. Book a call to discuss your application.
“The Firebase API key is not a secret—your Security Rules are your only data protection. Ship test mode to production and you have shipped with no authorization at all.”
Written by
Marco Silva
Security Engineer, Belsoft Solutions
More from the blog
Ready to partner?
Let's talk about your company.
30 minutes. No pitch. We talk through how you run today and where AI and automation would help.
Book a free audit
