Firebase security rules open to everyone: how to fix 'allow read, write: if true'
By Obscura Security · Updated · Firebase, Firestore, Cloud Storage, Realtime Database
Short answer
Rules like 'allow read, write: if true' mean anyone on the internet can read, change and delete your data, because your Firebase config is public by design. Replace them with rules that check request.auth.uid, and test them in the Rules Playground before you publish.
If your Firebase rules contain if true, or you started in “test mode” and never changed them, your database may be readable and writable by anyone who knows your project ID.
Why this happens
Firebase web apps talk to Firestore, Realtime Database and Cloud Storage directly from the browser. The config object in your frontend (apiKey, projectId and so on) is public, and Firebase says that’s fine. The only thing standing between a stranger and your data is your security rules.
Two things lead to open rules:
- Test mode. When you create a database in test mode, Firestore starts with a rule like
allow read, write: if request.time < timestamp.date(...), open to everyone until the date passes. When the date passes, the app starts failing, and the quick fix people (and AI tools) reach for is to extend the date or writeif true. - Rules written to make an error disappear. “Missing or insufficient permissions” is the error you see when rules block something. Changing the rule to
if truemakes it vanish.
How to check your own app
- In the Firebase console, open Firestore Database → Rules, and read what is published. Do the same for Realtime Database → Rules and Storage → Rules. Look for
if true, a future date inrequest.time <, or".read": trueand".write": true. - Use the Rules Playground (a tab in the Firestore and Storage rules editor) to simulate an unauthenticated read and write on a real path. If it says “Allowed”, the rule is open.
- From outside, for your own project, try the Firestore REST API with no login:
curl "https://firestore.googleapis.com/v1/projects/YOUR_PROJECT_ID/databases/(default)/documents/users"
A locked database returns a PERMISSION_DENIED error. A list of documents means it’s open.
For Realtime Database, open https://YOUR_DATABASE_URL/.json in a browser (the URL is shown at the top of the Data tab). “Permission denied” is what you want to see.
Only test projects you own.
The fix
The pattern is the same for every product: deny by default, then allow only what a signed-in user needs, based on request.auth.uid.
Firestore
If each user’s data sits in a document keyed by their ID, and other documents store an owner’s ID in a userId field:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// /users/{uid}: each person can only read and write their own profile
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
// /orders/{id} with a userId field
match /orders/{orderId} {
allow read: if request.auth != null
&& resource.data.userId == request.auth.uid;
allow create: if request.auth != null
&& request.resource.data.userId == request.auth.uid;
allow update: if request.auth != null
&& resource.data.userId == request.auth.uid
&& request.resource.data.userId == resource.data.userId;
allow delete: if request.auth != null
&& resource.data.userId == request.auth.uid;
}
}
}
Anything not matched by a match block is denied. The extra line on update stops a user changing userId to give a document to someone else.
For genuinely public data, such as published blog posts, allow reads only:
match /posts/{postId} {
allow read: if resource.data.published == true;
allow write: if false;
}
Realtime Database
{
"rules": {
"users": {
"$uid": {
".read": "auth != null && auth.uid === $uid",
".write": "auth != null && auth.uid === $uid"
}
}
}
}
Be careful with .read or .write set on a parent path. Rules in Realtime Database cascade downward, so a permissive rule high up can’t be taken back lower down.
Cloud Storage
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /users/{userId}/{allPaths=**} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}
Upload files to users/<uid>/... and only that user can reach them. For public images, such as product photos, add a separate allow read: if true; on that one folder and leave writes closed.
Test, then publish
Paste the rules into the editor, run signed-in and signed-out requests in the Rules Playground, then publish. Check your app still works for a normal user, and that a second test account can’t see the first one’s data.
Mistakes to avoid
- Leaving test mode on “for now”. The date passes and the problem comes back in a different form.
- Using
request.auth != nullas the only check. Anyone can create an account. - Trusting data the client sends. If a rule says
request.resource.data.role == 'admin', the user simply sendsrole: 'admin'. Store roles somewhere users can’t write. - Assuming queries are filtered by rules. Firestore rules aren’t filters. A query must be written so that it can only return documents the rules allow, or the whole query fails.
- Forgetting Storage. Firestore can be locked down while the Storage rules next door still say
if true.
Common questions
- Is it a problem that my Firebase apiKey is in my frontend code?
- No. The Firebase web config is meant to be public. It only identifies your project. What protects your data is your security rules, which is why open rules are the real problem.
- My test mode rules expired and the app broke. Can I just extend the date?
- That keeps your database open to everyone for another 30 days or so. Write real rules based on who the user is, then publish them.
- Is 'allow read, write: if request.auth != null' safe?
- It's better than 'if true', but it lets any logged-in user read and write everything. Anyone can sign up, so it is only slightly better. Rules should also check that the data belongs to the signed-in user.
- Do security rules apply to my server code?
- No. The Firebase Admin SDK, used in Cloud Functions or your own backend, bypasses security rules. That's why server code must do its own access checks.
Read next
Written by Obscura Security, an Australian practice that checks web apps for problems like this one. If you want a second pair of eyes on yours, email [email protected].