Storage buckets are not listable
Supabase or Firebase storage does not list objects to anonymous callers.
- Severity
- high
- Tier
- Verified: after you prove ownership
- Category
- Security
- Fix
- Summary below; full runbook in the Fix Kit, Module 03: Lock it down
- Id
- storage-bucket-listing
What this means
Passing means your Supabase or Firebase storage does not return a list of objects to an anonymous caller. Failing means a stranger can enumerate what your users uploaded: file names, folder names that are often user ids, and from there the documents themselves. A bucket that cannot be listed still needs each object protected, but listing is the step that turns a guess into an inventory.
How we test it
This check runs after you verify ownership (DNS TXT _securealy, the securealy-verify meta tag, or /.well-known/securealy.txt). We find the storage endpoint and public key your bundle ships and ask it, once, to list buckets and the objects in each, with no credential beyond that key. Pass is an empty list or a permission error. Fail is any bucket whose objects are listed.
Why it matters
Listable buckets leak uploads, IDs and documents. Storage sits beside the database on the same public key, so Module 3's rule 6 applies to it unchanged: the key ships in page source and the only thing between it and your files is a rule you set. A bucket that lists is the storage form of a table with row level security off, and it leaks a map of your users before a single file is opened.
The fix
Make every bucket private unless it is a public asset store on purpose, remove any policy that lets anonymous callers list or read storage objects, and serve private files from your server after the shared gate has run. Treat it like a table: locked by default, each opening written down, verified afterwards with one anonymous list request that returns nothing. The full runbook is in the Fix Kit, Module 03.
Prompt for your AI
Paste this into the coding agent that built the app. It reproduces the finding and stops before changing anything; the fix steps are in the kit.
Search the source for every storage bucket name the app uses (grep for .storage.from( and for bucket names in config) and list them. Using SUPABASE_URL and SUPABASE_ANON_KEY from .env.local, and never printing the key, make one anonymous request per bucket to list its objects and report for each: bucket name, status code, and how many object names came back. For each bucket that listed objects, tell me whether the code treats it as public (image assets) or private (user uploads). Read the storage policies in the repo's SQL files and quote any that apply to the anon role. Do not change any bucket, policy or file; list what it would take to close each listable bucket and stop. Re-run the one list request against the bucket you consider most sensitive and show me the output; expected for a passing project: an empty list or a permission error.
Grade your own URL
Every grade lists this check with its evidence for your site. Two free grades a day.