Firebase Security Rules: 12 Mistakes AI Tools Make
The 12 Firebase Security Rules mistakes AI builders ship — from allow read, write: if true to leftover test-mode rules — each with a quick before/after fix.
Your AI builder wrote your Firebase Security Rules for you. They worked, the demo looked finished, and you moved on. That's the problem — the most dangerous Firebase Security Rules mistakes are the ones that work perfectly while leaving your data open to the entire internet.
Security Rules are the rulebook Google runs on every read and write to your database and storage. They're your real security layer, because a Firebase app talks straight from the browser to Google with no backend server to check permissions. If the rules are wrong, nothing has to be "hacked" — the data is public. Below are the twelve mistakes AI tools make most, why the tool emits each one, and the before/after fix. You don't need to be a developer to follow along.
⚡ TL;DR
- AI builders optimize for "the app works in the preview," and open rules always work in the preview — so they ship
allow read, write: if trueand leave projects in test mode.- The most common mistakes: blanket access, test-mode leftovers, checking that someone is logged in but not that they own the data, no field validation, and forgetting Storage has its own rules.
- The pattern to remember: don't only check
request.auth != null— check that the user owns the specific document.
How to read a Firebase Security Rule (before the mistakes)
Two pieces of vocabulary and you'll follow every example below.
allow read, write— the actions a rule permits.if <condition>— the test that must pass.if truemeans "always allow."if request.auth != nullmeans "allow any logged-in user."if request.auth.uid == userIdmeans "allow only the user who owns this document."
The single most important idea in this post: being logged in is not the same as being allowed. Most leaks live in that gap.
1. allow read, write: if true — the open door
The most common and most dangerous rule — it lets anyone on the internet read and write everything. AI tools emit it because open rules make every feature work instantly in the preview. Replace the wide-open if true with auth plus an ownership check:
// BEFORE: allow read, write: if true;
// AFTER — require auth and ownership
match /users/{userId} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
2. Leftover test-mode rules (open for 30 days)
When you start a Firebase database, the console offers test mode, which allows full access until a date about 30 days out. AI walkthroughs lean on it to skip auth; people forget the timer and ship wide open.
// BEFORE — test mode: open until a hardcoded date
match /{document=**} {
allow read, write: if request.time < timestamp.date(2026, 7, 29);
}
// AFTER — real rules, no expiry, scoped to the owner
match /notes/{noteId} {
allow read, write: if request.auth != null
&& request.auth.uid == resource.data.ownerId;
}
A countdown to "open" is not security. Write real, owner-scoped rules before you go live.
3. request.auth != null with no ownership check
The most subtle mistake, because it looks responsible. It requires a logged-in user — but then lets that user read or write everyone's data; any signed-up account can pull the whole collection. It happens because "make it require login" is a common instruction, and request.auth != null satisfies it literally.
// BEFORE: allow read: if request.auth != null;
// AFTER — a user reads only documents they own
match /messages/{messageId} {
allow read: if request.auth != null
&& request.auth.uid == resource.data.userId;
}
⚠️ Watch out
request.auth != nullis the rule that passes a casual review and still leaks everything. If your app has more than one user, every rule needs an ownership check, not a login check alone.
4. Rules applied to the wrong path
Firebase rules match document paths. If the path doesn't match where your data lives, the rule silently does nothing and a broader rule takes over. It happens because the rules and the data-writing code are generated separately and drift — a singular/plural mismatch, a renamed collection.
// BEFORE — protects /profile, but data lives in /profiles
match /profile/{userId} {
allow read, write: if request.auth.uid == userId;
}
// AFTER — path matches the real collection name
match /profiles/{userId} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
5. No field validation on writes
A rule can check who is writing but not what they write. Without validation, a user can flip their own role to admin, change a price, or write malformed data your app trusts. AI tools skip this because it requires knowing your data model and which fields are sensitive.
// BEFORE — owner can write any fields, including role
match /users/{userId} {
allow write: if request.auth.uid == userId;
}
// AFTER — block privilege fields, validate shape
match /users/{userId} {
allow write: if request.auth.uid == userId
&& request.resource.data.role == resource.data.role
&& request.resource.data.email is string;
}
6. Forgetting Storage has its own separate rules
This causes the worst breaches. Firebase Storage (files, images, uploads) uses a different rulebook from your database. Lock the database, feel safe, and your file bucket can still be wide open — anyone who guesses a URL downloads users' photos, documents, and IDs.
// BEFORE — Storage open to anyone
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if true;
}
}
}
// AFTER — users read/write only their own folder
service firebase.storage {
match /b/{bucket}/o {
match /user-uploads/{userId}/{fileName} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
}
}
This exact gap is how the Tea app exposed roughly 72,000 images, including about 13,000 selfies and government IDs — an unsecured legacy Storage bucket, not a cracked key. We cover it in the Tea app breach, and Storage rules in depth in open Storage buckets: the #1 Firebase leak.
7. Treating the apiKey as if it were a secret
Not a rules typo, but a mistake that warps every fix that follows: assuming the Firebase web config / apiKey in your frontend is a leak, then "securing" it by rotating or hiding it while the actual rules stay open. The apiKey is public by design — it identifies your project, it does not grant access. A key-shaped string in frontend code trips naive secret-scanners, which flag it and send you to fix the wrong thing.
🐺 Not a real problem
An exposed Firebase web config /
apiKeyis not a leak. If a tool told you to rotate it, that tool is crying wolf. The credential that's actually secret is the server-side service-account key, which bypasses every rule. See what's public vs secret.
8. Client-side checks only
Your app's UI might hide the delete button from non-owners. That's user experience, not security — anyone can ignore your UI and call Firebase directly with the public config. If the rule doesn't enforce it, it isn't enforced.
// BEFORE: allow delete: if request.auth != null; // "the UI hides this"
// AFTER — the rule itself enforces ownership
match /posts/{postId} {
allow delete: if request.auth != null
&& request.auth.uid == resource.data.authorId;
}
9. Overusing {document=**} recursive wildcards
The {document=**} pattern matches a collection and everything nested under it. A permissive rule high up cascades down to subcollections you never meant to expose. Scope rules to membership at the right level instead:
// BEFORE: match /workspaces/{wid}/{document=**} { allow read: if request.auth != null; }
// AFTER — check membership per level
match /workspaces/{wid} {
allow read: if request.auth != null
&& request.auth.uid in resource.data.memberIds;
}
10. Public-read collections that shouldn't be public
Sometimes a collection truly should be world-readable (a public blog). AI tools over-apply that pattern, marking user profiles or order data allow read: if true because something nearby needed public read.
// BEFORE: allow read: if true;
// AFTER — readable only by signed-in users (or only the owner)
match /profiles/{userId} {
allow read: if request.auth != null;
}
11. No rules at all on a new collection
Rules only protect paths they explicitly match. Add a collection later — payments, invites — and if no rule covers it, access falls back to your defaults, which after AI scaffolding are often permissive. The tool adds the feature but doesn't circle back to write a matching rule, so the collection quietly ships unprotected.
// AFTER — add an explicit, locked rule whenever you add a collection
match /payments/{paymentId} {
allow read: if request.auth != null
&& request.auth.uid == resource.data.userId;
allow write: if false; // only your server (Admin SDK) writes payments
}
12. Never enabling App Check
Even with perfect rules, anyone can take your public config and call your backend from a script, impersonating your app. App Check attaches a verifiable token proving a request came from your genuine app, so Firebase can reject random bots and scrapers. AI builders skip it because it isn't required to make features work — not an emergency, but the layer that keeps strangers' scripts off your backend.
How to check your own app
You can audit all twelve in about fifteen minutes, no code required.
- Open Firestore (or Realtime Database) → Rules and read them. Flag any
if true, anyrequest.time < timestamp.date(...)test-mode line, and any rule that stops atrequest.auth != nullwithout an ownership check. - Open Storage → Rules separately — the step that catches mistake #6. Make sure your file bucket isn't open.
- Match every rule path to a real collection name (mistake #4): a rule on
/profilewhile data lives in/profilesprotects nothing. - Confirm each collection has a matching, locked rule — especially anything added after the initial build (mistake #11).
- Check App Check, and stop worrying about the public
apiKey(mistake #7).
Not sure if your app has this exact issue?
Run a free, read-only scan of your live app — no install, results in under a minute.
Scan my app free →The one-prompt fix
You can have your AI tool do most of the cleanup, but check its work against the list above — the same tool that made the mistake can over-correct. A solid starting prompt:
"Review my Firestore and Storage Security Rules. For every collection and storage path: require request.auth != null AND verify the logged-in user owns the document or file (compare request.auth.uid to the owner field). Remove any allow read, write: if true and any test-mode time-based rules. Add field validation so users can't change privilege fields like role. Scope Storage rules to per-user folders. Do not touch the public web config. List every change and why."
Then re-read the rules yourself. If a rule still ends at request.auth != null for a multi-user collection, it's not done.
FAQ
What does allow read, write: if true mean in Firebase?
It means anyone on the internet can read and write that data, logged in or not — no protection at all. It's the single most dangerous Firebase rule, and a common AI default because it makes every feature work in the preview. Replace it with rules that require authentication and check ownership.
Is checking request.auth != null enough to secure Firebase?
No — this is the most common subtle leak. request.auth != null only confirms the user is logged in; it still lets any account read or write everyone's data. You also need an ownership check comparing request.auth.uid to the owner field on the document.
Do Firebase Storage and Firestore share the same rules?
No. They use separate rulebooks. You can have a perfectly locked database and a wide-open file bucket at once. Review Storage rules on their own — open buckets are how the worst Firebase breaches, like the Tea app, happened.
The bottom line
Almost every Firebase Security Rules mistake comes down to one habit: the AI optimized for "it works in the preview," and open rules always work in the preview. The fix is to check ownership, not login alone; remember Storage has its own rules; and stop chasing the public apiKey. An attacker can probe your rules in minutes — so find these twelve first, and re-check every time your AI adds a collection or a bucket, because that's when new gaps appear.
Find your gaps before an attacker does.
Is My Site Hackable? scans your deployed app for the exact issues in this article — exposed keys, missing RLS, open buckets — and tells you what's real and what's a false alarm.
Run a free scan →