Firebase will store data for an app an AI builder just scaffolded. The API key in the JavaScript isn't the lock. Firebase's API keys page says keys for Firebase services are public by design. They identify the project and the app. Authorization is Firebase Security Rules, plus Google Cloud IAM and App Check. The security checklist repeats it: don't rely on hiding the key. Secure Realtime Database, Cloud Firestore, and Cloud Storage with rules.
The mistakes below are the ones Firebase documents under avoid insecure rules. They show up when a chat says "make the read work" and the model writes the rule that always allows the read. I'm not making any claim about how often that happens. This is just a list you can check in the Firebase console before you share the URL.
Test mode is a choice, and it is wide open
When you create a database or a Cloud Storage bucket in the console, Firebase lets you deny access to all users (locked mode) or grant access to all users (test mode). The docs say a more open setup can make sense while you're developing, and that you should configure the rules before you deploy the app. The security checklist says to initialize Cloud Firestore in production mode and Realtime Database in locked mode, then add rules that grant access as you go. For Cloud Storage, the checklist shows a starting rule of allow read, write: if false.
An AI builder doesn't sit in that console dialog with you. It may ship client code that reads Firestore on the first screen, and it may also write a rules file. Open the Firebase console, pick the project, and open Rules under Realtime Database, Cloud Firestore, and Storage. The console shows the rules that are actually deployed. A local file in the repo can be stricter than what is live, or the other way around. Trust the deployed copy.
Open access
Firebase labels this as not recommended. For Cloud Firestore, the sample they tell you never to use in production is a match on /{document=**} with allow read, write: if true. For Realtime Database, the sample is ".read": true and ".write": true at the root. For Cloud Storage, the sample allows read and write on /{allPaths=**} with no condition. Their warning is specific: anyone can overwrite the database or the files.
If your rules file contains if true on a wildcard path, or a root ".read": true, the data is public to anyone who knows the project. Firebase also says that if you aren't authenticating users and configuring rules, anyone who guesses the project id can read, change, or delete the data. The project id is in the client config next to the API key. It isn't a secret either.
The documented direction is user-based rules with Firebase Authentication. Their content-owner sample allows a read or a delete when request.auth.uid equals resource.data.author_uid, and a create when it equals the new document's author_uid. Realtime Database's version compares auth.uid to a $uid path. You don't have to copy those samples line for line. You do have to replace true.
Any signed-in user
The second pattern Firebase calls out is a rule that only checks that someone is logged in. Firestore: allow read, write: if request.auth.uid != null on a whole collection. Realtime Database: ".read": "auth.uid !== null" at the root. Storage: allow read, write: if request.auth != null on every path.
Firebase's point is that this gives every logged-in user read and write access to everything that rule covers. That can be what you want for a tiny shared scratch pad. It's a poor fit for a table of customer records, inboxes, or files. If one account can read another account's documents, the rule is the reason. Narrow it with a user id on the document or the path, the way the content-owner samples do.
A related trap is turning on a provider so the demo can "sign in" without a password, then writing auth != null and calling it private. The rule is doing exactly what it says. It just doesn't match what most people mean by private.
Realtime Database rules cascade
Realtime Database has a rule the other products don't. Rules cascade. A read allowed at a parent path can't be taken back by a child. Firebase's sample sets ".read" on foo, then sets ".read": false on foo/bar, and says the child rule is ignored because the parent already allowed the read. A builder that "locks down" a nested path while leaving ".read": true higher up hasn't locked anything under that parent.
Write the broad denies at the parent, and grant the extra access on the child paths that should be readable. If you need per-user data, put the user id in the path and allow read and write only when auth.uid equals that id. Don't allow the root and then try to deny the leaves.
Closed rules, and the Admin SDK
The other sample Firebase shows is closed access: allow read, write: if false, or ".read": false and ".write": false. They say the Admin SDK and Cloud Functions can still read and write. Use closed rules when the database is a server-only backend. Clients will fail on purpose. If the app in the browser reads Firestore directly, closed rules will make that screen fail, and the next chat will be tempted to flip them to true. Put the direct client read behind a real rule, or move the read to a server that uses the Admin SDK and keep the client rules closed. Pick one. Don't do half of each.
Firebase also notes that the server client libraries bypass Cloud Firestore Security Rules and authenticate with application credentials instead. A service account in client code is a different and worse problem than a public API key. The API key identifies the app. The service account is a credential. It belongs on a server.
The API key, App Check, and other Google APIs
Review restrictions, but don't confuse them with rules. Firebase says every Firebase-provisioned API key should be restricted to the Firebase APIs you use, and that a key for some other Google API (they name the Places API and the Gemini Developer API) should be a separate key. The checklist says not to add the Gemini Developer API to the allowlist of a key that ships in the client. If the builder pasted one Google key and used it for both Firebase and a generative API, split them.
App Check is how Firebase tells which app is calling, as opposed to which person. The API keys page says App Check, not key secrecy, protects covered APIs from abuse by other apps. Rules still decide which end user can touch which document. When the product is public, you want both. The free page check described below doesn't test App Check. Turn it on in the console if you're going to rely on it, and read Firebase's setup for your platform rather than assuming the client key implies it.
What a free check can see
Deploy Safely looks at the public page and the scripts that page loads. It doesn't open the Firebase console, and it doesn't read your rules file unless that file happens to be sitting in the public JavaScript.
The Firebase check runs only when the page already contains the config. A Realtime Database URL (a firebaseio.com or firebasedatabase.app host) is enough for a signed-out read of /.json with a shallow, one-item look. If that response is data rather than a refusal, the report says the database answered a visitor. It doesn't save the data. If the response is 401 or 403, the check notes the refusal and doesn't call the database safe, because rules can still be open on a path that this one request didn't hit.
Firestore is checked only when both a projectId and a public web API key are already in the page. The check asks the public Firestore documents endpoint for a single document, using that key and no login. If a document comes back, the report names the collection and doesn't save the document. Cloud Storage rules aren't part of this check. A Google API key in the page may be noted as a low-severity reminder to restrict it, which matches the idea that the key is expected and still worth restricting. It isn't reported as a secret of the same kind as a service account.
The same pass looks for other leaked secrets in the page and scripts, requests /.env, /.git/HEAD, /.git/config, and /.npmrc, and notes missing security headers on the main response when two or more of the watched headers are absent. It doesn't log in, deploy rules, or guess collection names beyond what that single public request returns. Use the checklist for the console steps. If a builder connected Firebase for you, the Replit, Cursor, and v0 guides are the matching short pages.
A prompt you can paste
Paste this into the builder, publish again, and run the check a second time. If a secret was already on the live site, rotate it in that vendor's dashboard. The prompt cannot do that part.
Review Firebase Security Rules for this app and replace any open rule. Do not print secrets in your reply. 1. Open the rules you would deploy for Cloud Firestore, Realtime Database, and Cloud Storage. Replace allow read, write: if true, and root ".read": true or ".write": true, with rules that match the signed-in user to the document or path they own. 2. Do not leave a rule that only checks request.auth != null on an entire database, unless that data is meant for every signed-in user. Say which collections are shared on purpose. 3. On Realtime Database, do not allow a parent read and then deny a child. Parent allows cannot be revoked lower down. 4. Keep the Firebase web API key in the client. Never put a service account JSON or a private key in client code. If a Google key is also used for a non-Firebase API, split that into a separate restricted key. 5. Tell me the rule files you changed. I will deploy them in the Firebase console and confirm a signed-out request is denied. Do not set a rule to true so a screen will load.