Fix guide · critical · firebase_rtdb_open
Firebase Realtime Database root readable without authentication
A GET to https://<project>.firebaseio.com/.json returned data without an auth token. Your RTDB security rules grant .read: true at the root — every node in the database is enumerable by anyone with the project ID (which is in your client bundle).
Why it matters
RTDB's default rules in test mode grant ".read": true, ".write": true at the root. The Firebase Console explicitly warns this is for development only and locks them after 30 days — but apps regularly ship before the lockdown fires, or devs extend the timer to keep dev moving. Once a single attacker pulls /.json, they have the entire database. The shape isn't theoretical; the same misconfiguration produced the FireStorage exposure scans in 2023 and surfaces in every fingerprinting tool today.
How to fix it
Replace the rules with explicit, path-scoped policies. Console → Realtime Database → Rules:
{
"rules": {
".read": false,
".write": false,
"users": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid"
}
},
"posts": {
".read": "auth != null",
"$postId": {
".write": "auth != null && (!data.exists() || data.child('authorId').val() == auth.uid)"
}
}
}
}
Key principles:
- Default-deny at the root.
".read": false, ".write": falseat the top stops the whole-tree dump. - Grant access at the leaf. Each path explicitly says who can read or write what.
- Use
$uidand$postIdvariables to enforce ownership instead of trusting client-supplied IDs. - Validate writes. Add
.validaterules with type and shape checks; otherwise authenticated users can still write garbage.
After publishing rules, run the Rules Playground (Console → Rules → Simulator) with auth=null to confirm nothing returns. Then with a test UID to confirm only that user's nodes are reachable.
Full guide: /blog/firebase-rules-vibe-coded.
Did vibecheck flag this on your app?
If you reached this page from a vibecheck inspection report, the redacted match in your scan output is the exact string we found in your bundle. After applying the fix above, run the inspection again — the finding should clear.
Run another inspection