Fix guide · high · firebase_storage_public_list
Firebase Storage bucket allows anonymous list
A GET to https://firebasestorage.googleapis.com/v0/b/<bucket>/o returned an object listing without an auth token. Your Storage rules permit anonymous reads on the default bucket — which means every file path is enumerable.
Why it matters
Storage rules follow the same request.time < ... test-mode shape as Firestore, with the same shipping pattern: apps go live before the date passes. The List API needs only allow read: if true (or a permissive match /{allPaths=**} block) to expose every object's path. Once an attacker has the path list, individual files can be retrieved over the same public REST endpoint — ID cards, receipts, screenshots, anything the app uploads.
How to fix it
Lock the rules to authenticated, path-scoped access. Console → Storage → Rules:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
// Default: deny.
match /{allPaths=**} {
allow read, write: if false;
}
// Profile photos: any signed-in user can read; only the owner can write.
match /users/{userId}/avatar.jpg {
allow read: if request.auth != null;
allow write: if request.auth != null
&& request.auth.uid == userId
&& request.resource.size < 5 * 1024 * 1024
&& request.resource.contentType.matches('image/.*');
}
// Public assets the marketing site needs.
match /public/{file} {
allow read: if true;
allow write: if false;
}
}
}
Key principles:
- Default-deny. Same shape as Firestore — explicit closed policy, then specific opens.
- Validate uploads.
request.resource.sizeandrequest.resource.contentTypeprevent users from uploading 4 GB of arbitrary binary as their "avatar". - Use path scoping for multi-tenant.
/users/{userId}/...paired withrequest.auth.uid == userIdenforces per-user isolation in one rule. - Audit the public/ namespace separately. If you do need a public read path, keep its scope tight and never let it permit writes.
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