Skip to main content
interlace
SecurityPlugin: supabase-securityRules

no-public-storage-bucket

Do not create a Supabase storage bucket as public

Do not create a Supabase storage bucket as public.

Why

A public bucket serves every object in it to anyone with the URL: no session, no RLS check, no expiry. That is a decision about the bucket's whole future contents, taken once, in one argument, at creation — long before anyone uploads the file that should not have been public.

Object names are guessable far more often than teams expect: sequential ids, e-mail addresses, original filenames from a user's disk. "Nobody knows the URL" is not access control.

Rule details

Fires only in files importing a @supabase/* package. Reports createBucket() or updateBucket() whose options object sets public: true as a literal.

Not in recommended, on purpose: a bucket of site assets is legitimately public, and this rule cannot tell that from a bucket of invoices. It is in strict, where the intent is to review every one.

Abstains on a spread and on a non-literal value — both are unreadable from the call site.

Incorrect

import { createClient } from '@supabase/supabase-js';

await db.storage.createBucket('user-documents', { public: true });

Correct

import { createClient } from '@supabase/supabase-js';

await db.storage.createBucket('user-documents');

// Hand out time-limited access per object instead.
const { data } = await db.storage
  .from('user-documents')
  .createSignedUrl(path, 60);

Further reading

Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.