"allow read, write: if true" — the Firestore rules gap nobody fixes in time
- Test-mode rules expire in 30 days. Most projects extend them for 30 more. And 30 more. Your Firestore is a public Google Doc until you write real rules.
- What passes the audit. Explicit paths per collection, ownership checks (
request.auth.uid == resource.data.owner), and a deny-all fallback on/{document=**}. App Check on. Anonymous auth off. - Check it in CI. A Firebase rules file is just text. A deep scan on every push catches a regression the moment someone copy-pastes
if trueback in.
When you create a new Firestore database, Firebase gives you two options: "start in production mode" (deny everything, you write rules) or "start in test mode" (allow read, write: if true for 30 days).
Most people pick test mode because they want to see their app work.
Test mode rules expire in 30 days. In practice, they expire when you notice the Firebase dashboard's yellow banner telling you they've expired — which is usually a lot longer than 30 days, because "extend" is one click and writing proper rules is fifty.
What the rules actually look like
The default test-mode Firestore rules ship like this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
Translation: any caller, authenticated or not, can read and write any document in any collection. Including documents they didn't create. Including other users' profiles. Including documents they've never heard of.
The same pattern exists for Storage: allow read, write: if true; on /{allPaths=**} means anyone can upload files to your storage bucket. The most common outcome of this one is a crypto-mining worm finding your project and filling the bucket with payloads, followed by a very large Google Cloud bill.
What our Firebase provider actually checks
Give us your project_id (and optionally a service account JSON — read-only permissions only) and the Firebase provider authenticates via the Firebase Admin API to pull:
- Firestore rules (
firestore.rules) — parsed and scanned forif true, missing deny-all fallbacks, overly permissiverequest.auth != nullpatterns (which lets any signed-up user read every other user's data), andallow writepaths without ownership checks. - Storage rules (
storage.rules) — same checks, scoped to bucket paths. - Realtime Database rules — if the project uses RTDB, we check for
".read": trueand".write": true. - App Check status — whether anti-abuse protection is enabled. If not, your Firebase is callable from any client, which defeats client-side rate limiting.
- Anonymous auth — enabled-by-default on a lot of projects. Combined with
request.auth != nullrules, this means anyone can sign up anonymously and access everything.
What a passing rules file looks like
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if request.auth.uid == userId;
allow write: if request.auth.uid == userId;
}
match /posts/{postId} {
allow read: if true; // public feed
allow create: if request.auth.uid == request.resource.data.author;
allow update: if request.auth.uid == resource.data.author;
allow delete: if request.auth.uid == resource.data.author;
}
match /{document=**} {
allow read, write: if false; // deny-all fallback
}
}
}
Three things to notice:
- Explicit paths per collection. No
{document=**}at the top with permissive rules. - Ownership checks on writes via
request.auth.uid == resource.data.author. - A deny-all fallback at the bottom so forgotten collections don't fail open.
Audit your project
A deep scan with your Firebase project ID takes a minute or two and tells you exactly which rules are permissive, which are correct, and which are fine but missing a fallback. Start here.
Keep it tight on every push
Firestore rules are a text file in your repo. The moment someone edits that file, the scan should run:
- GitHub Action — watches for
firestore.rulesandstorage.ruleschanges on every PR, fails the build when a permissive rule is re-introduced. - GitLab CI template — same guardrail, native GitLab.
Don't ship until you're sekrd
Run a free scan to find the vulnerabilities your AI missed.
Scan Your App Free