Buckets públicos en Supabase Storage: ¿están expuestos los archivos de tus usuarios?
Los avatares pueden ser públicos; los documentos, facturas y contratos, no. Cómo revisar los buckets y reglas de Supabase Storage y corregirlos sin romper nada.
4 min de lectura
La mayoría de las apps hechas con Lovable, Bolt y herramientas similares permiten al usuario subir algo: una foto de perfil, un recibo, un contrato, una foto de su documento para verificarlo. En Supabase, esos archivos van a Storage, organizados en buckets.
Cuando una herramienta de IA crea un bucket, a menudo lo hace público, porque así las imágenes se ven sin trabajo extra. Para un logo está bien. Para cualquier cosa personal, significa que cualquiera con el enlace puede descargar el archivo, y a veces cualquiera puede listar todos los archivos del bucket.
Esta guía es la mitad de Storage de nuestra revisión de Supabase en 10 minutos. Lleva más o menos lo mismo.
Buckets públicos y privados
| Bucket público | Bucket privado (el predeterminado) | |
|---|---|---|
| Descargar un archivo | Cualquiera con la URL, sin comprobar reglas | Solo si una regla lo permite, o con un enlace firmado que caduca |
| Subir, borrar, mover | Lo controlan tus reglas | Lo controlan tus reglas |
| Listar los archivos | Lo controlan tus reglas | Lo controlan tus reglas |
De esta tabla se deducen dos cosas:
- Un bucket público se salta tus reglas por completo en las descargas. Si las rutas de los archivos son predecibles (
invoices/1043.pdf,ids/user-15.jpg), un desconocido puede adivinarlas. - Hacer privado un bucket no sirve de nada si las reglas de
storage.objectsdejan que cualquiera lo lea todo. Las reglas de Storage son políticas normales de Row Level Security sobre esa tabla, y una regla demasiado amplia abre un bucket privado igual de bien.
Paso 1: lista tus buckets
En el panel de Supabase, abre el SQL Editor y ejecuta:
select id, public, file_size_limit, allowed_mime_types
from storage.buckets
order by public desc, id;Para cada fila con public = true, hazte una pregunta: ¿me parecería bien que todos los archivos de este bucket aparecieran en un buscador? Imágenes de productos, sí. Cualquier cosa que un usuario haya subido sobre sí mismo, no.
Mira también las dos últimas columnas. Si los límites están vacíos, cualquiera que pueda subir archivos puede guardar uno de cualquier tamaño y cualquier tipo en tu proyecto, a tu costa.
Paso 2: lee las reglas de Storage
select policyname, cmd, roles, qual, with_check
from pg_policies
where schemaname = 'storage' and tablename = 'objects'
order by cmd, policyname;Qué buscar:
- Una regla
SELECTparaanonopubliccuya condición sea solobucket_id = '…'. Permite a cualquiera listar y leer todos los archivos del bucket. - Una regla
INSERTparaanon, o paraauthenticatedsin condición de carpeta. Permite a cualquier usuario subir archivos en cualquier sitio, incluso encima de las rutas de otros usuarios si también hay una reglaUPDATEabierta. - Una regla
DELETEque no vincula el archivo con su dueño.
El Security Advisor del panel también señala algunos de estos casos. Revísalo después de cada cambio.
Paso 3: compruébalo desde fuera
Con solo la URL del proyecto y la clave pública (en Project Settings → API Keys), intenta listar un bucket como lo haría un desconocido:
curl -X POST "https://YOUR-PROJECT.supabase.co/storage/v1/object/list/BUCKET_NAME" \
-H "apikey: YOUR_PUBLIC_KEY" \
-H "Content-Type: application/json" \
-d '{"prefix": "", "limit": 20}'Si devuelve nombres de archivos de un bucket que guarda archivos privados, el listado está abierto. Repite con cada bucket que contenga algo personal.
Cómo corregirlo
Mueve los archivos personales a un bucket privado
Crea un bucket privado (por ejemplo, documents) para todo lo que identifique a una persona o contenga datos del negocio. Deja un bucket público solo para los archivos que deben ser públicos.
Después, cambia cómo muestra la app esos archivos. En lugar de una URL pública permanente, pide a Supabase una URL firmada que caduca, por ejemplo en una hora. Con el cliente de JavaScript, es createSignedUrl(path, 3600). Los enlaces públicos antiguos dejan de funcionar al hacer el cambio, así que planifícalo junto con el cambio de código, no antes.
Dale a cada usuario su propia carpeta
El patrón habitual es subir cada archivo dentro de una carpeta con el ID del usuario, como documents/8f1c…/contract.pdf, y escribir reglas que lo comprueben:
create policy "Read own documents"
on storage.objects for select
to authenticated
using (
bucket_id = 'documents'
and (storage.foldername(name))[1] = (select auth.uid()::text)
);
create policy "Upload to own folder"
on storage.objects for insert
to authenticated
with check (
bucket_id = 'documents'
and (storage.foldername(name))[1] = (select auth.uid()::text)
);Añade reglas de update y delete con la misma condición si los usuarios pueden reemplazar o eliminar sus archivos. Subir con la opción de sobrescribir activada requiere select, insert y update.
Buckets públicos: que se puedan leer, pero no listar
Un bucket público de avatares no necesita ninguna regla SELECT para las descargas, porque las URL públicas se saltan las reglas. Elimina las reglas SELECT amplias para anon en buckets públicos, salvo que la app de verdad necesite listar su contenido.
Pon límites
Dale a cada bucket un tamaño máximo de archivo y una lista de tipos permitidos (por ejemplo, image/png, image/jpeg, application/pdf). Lleva un minuto en la configuración del bucket y evita que tu Storage se convierta en hosting gratuito para otra persona.
Si tu app maneja documentos, identificaciones o registros de pago y quieres que alguien lo revise contigo, nuestro Security Check gratuito revisa Storage junto con las reglas de la base de datos, las claves y la autenticación, en modo de solo lectura y desde fuera.
SupabaseRow Level SecurityApps hechas con IA
Este artículo también está disponible en: EnglishPortuguês日本語中文
Sigue leyendo
Todos los artículos
Seguridad de apps
Antes de lanzar una app hecha con Lovable: lista de seguridad previa al lanzamiento
Quince comprobaciones antes de que lleguen usuarios y datos reales: reglas, claves, storage, inicio de sesión, pagos, funciones y copias. Casi todas en minutos.
4 min de lectura

Seguridad de apps
¿Claves de OpenAI o Stripe en tu app hecha con IA? Llévalas a una función en el servidor
Cualquiera puede copiar una clave del frontend. Qué claves pueden ir en el navegador, cómo encontrar las que no y cómo moverlas a una Edge Function de Supabase.
4 min de lectura

Seguridad de apps
¿Encontraste tu clave secreta de Supabase en el navegador? Qué hacer en la primera hora
Una clave service role o secreta en el frontend da acceso total a tu base de datos. El orden correcto: revocar, reemplazar, revisar logs y corregir la causa.
5 min de lectura