01 de ago. de 2025·6 min de leitura

Auditoria de exposição de buckets: pare arquivos públicos e a listagem

Checklist de auditoria para exposição de buckets: identifique ACLs públicas, permissões padrão arriscadas e regras de upload inseguras para manter arquivos privados realmente privados.

Auditoria de exposição de buckets: pare arquivos públicos e a listagem

Como a exposição de um storage bucket aparece na prática

Um storage bucket é uma pasta grande na nuvem onde um app guarda arquivos: fotos de perfil, faturas, notas de áudio, relatórios exportados e qualquer coisa que os usuários façam upload. Equipes gostam de buckets porque são baratos, rápidos e fáceis de conectar ao app.

A exposição geralmente não acontece porque alguém “invadiu” o bucket. Acontece porque uma configuração ficou aberta durante um protótipo, uma demo ou um lançamento apressado. Um checkbox pode tornar o bucket inteiro público. Ou alguém assume “privado por padrão” quando o padrão é permissivo.

A exposição tipicamente aparece de duas formas:

  • Público: qualquer pessoa pode buscar um arquivo e, às vezes, listar o bucket inteiro como um diretório.
  • Não listado mas adivinhável: os arquivos não são indexados, mas o padrão de URL é previsível, então é possível adivinhar nomes como uploads/user_123/id.jpg ou tentar nomes comuns.

O segundo é mais sorrateiro. Um fundador pode testar um upload “privado”, ver que não aparece no app e assumir que está seguro. Mas se o link puder ser adivinhado (ou compartilhado casualmente), ele continua, na prática, público.

Prototipação é onde isso costuma começar. Ferramentas que geram apps rapidamente podem usar regras simples como “permitir leitura para todos” para que nada quebre durante uma demo. Depois o protótipo vira produção e o bucket mantém as configurações da demo.

Uma auditoria de exposição de storage buckets procura esses pontos de falha do mundo real antes que se tornem uma violação: flags de acesso público, defaults permissivos e regras de upload que tornam arquivos privados fáceis de buscar ou listar.

Faça um inventário dos buckets e do que contêm

Comece pelo passo pouco glamouroso: escreva cada bucket e para que ele é usado. Muitos vazamentos acontecem nos buckets “extras” que ninguém lembra, como exports, backups ou projetos antigos de staging.

Mapeie buckets para funcionalidades reais do app. Se seu app deixa pessoas fazerem upload de avatares, anexar faturas, enviar imagens em chat ou exportar relatórios CSV, cada uma dessas funcionalidades escreve arquivos em algum lugar. Não confie em suposições — verifique o código e o console da nuvem para capturar o quadro completo.

Em vez de organizar por nome de time, organize pelo que os arquivos são:

  • Uploads de usuário (fotos, documentos, áudio)
  • Arquivos gerados (PDFs, thumbnails)
  • Exports e relatórios
  • Backups e snapshots
  • Artefatos internos (logs, outputs de build)

Para cada categoria, registre três coisas: onde os arquivos vivem (bucket mais path/prefixo), como os arquivos chegam lá (qual serviço ou endpoint grava) e por quanto tempo devem permanecer.

Depois decida quem deveria poder ler cada tipo de arquivo. “Todo mundo na internet” deve ser raro. Muitas equipes marcam algo como “público” quando só precisa ser legível por usuários logados ou por um cliente específico e sua equipe de suporte.

Uma checagem rápida de sanidade para cada bucket ou prefixo:

  • Esse conteúdo é realmente para ser público para sempre?
  • Se for privado, quem exatamente pode ler?
  • O que acontece se alguém adivinhar um nome de arquivo?
  • Os links precisam expirar?

Checklist rápido: 5 verificações que você pode fazer hoje

Você pode aprender muito em 15 minutos testando o que um estranho aleatório pode fazer sem acesso. Faça essas cinco verificações e registre ok/falha para cada bucket:

  • Abra a URL real de um arquivo em uma janela privada. Se carregar sem login, trate como público.
  • Verifique se a listagem é possível. Se você conseguir navegar objetos (ou receber uma resposta tipo índice), está perto de um vazamento completo.
  • Percorra o fluxo de upload de ponta a ponta. Se uploads funcionam sem autenticação, ou o servidor não valida restrições básicas, assuma que abuso é possível.
  • Observe padrões de URL. Se chaves incluem nomes de usuário, timestamps, números de pedido ou IDs simples, as pessoas podem adivinhar URLs e coletar arquivos.
  • Busque por “strays” sensíveis como arquivos .env, dumps de banco, backups, logs exportados ou pastas temporárias.

Um reality check rápido: se seu app salva fotos de perfil como /uploads/jane-1700000000.png, mesmo um bucket não listável pode vazar por adivinhação.

Verifique configurações de acesso público e ACLs

Comece no nível do bucket. Um único toggle “público” pode sobrepor a lógica cuidadosa do app e tornar todo objeto acessível por quem adivinhar uma URL.

Controles de acesso público costumam existir em mais de um lugar: uma configuração do bucket (bloquear acesso público), uma política de bucket (quem pode ler ou listar) e ACLs de objeto (permissões por arquivo). Se qualquer camada permitir leitura anônima, arquivos privados podem vazar.

O que verificar primeiro:

  • Confirme se o bucket bloqueia acesso público na configuração.
  • Confirme se a listagem está bloqueada. Listagem pública costuma ser pior que leituras públicas porque expõe tudo.
  • Faça scan por padrões de ACL em objetos como public-read em uploads de usuário.
  • Registre quem é o dono do bucket (conta/projeto/role de serviço) e quem pode mudar as configurações.

As ACLs merecem atenção extra porque podem ser aplicadas arquivo a arquivo. Um caminho de upload com bug pode criar arquivos públicos silenciosamente mesmo que a política do bucket pareça correta.

Se encontrar qualquer acesso público, trate como urgente. Tranque leituras e listagem primeiro. Depois corrija defaults e regras de upload para que o problema não volte.

Reveja permissões padrão e políticas herdadas

Muitos vazamentos ocorrem porque o bucket não está “público” no papel, mas novos arquivos herdam permissões que os tornam legíveis de qualquer forma. A maior vitória rápida é confirmar o que acontece por padrão quando seu app sobe um objeto novo.

Verifique defaults no nível do bucket para uploads novos. Algumas configurações aplicam uma ACL padrão ou uma permissão canned que torna objetos legíveis por qualquer pessoa com a URL.

Depois revise políticas que se aplicam acima do bucket. Uma política de bucket pode sobrepor configurações por arquivo, e uma regra em nível de conta pode sobrepor o bucket. Regras amplas como leitura para “todos os usuários” (ou qualquer princípio global equivalente) são fontes comuns de exposição surpresa.

Verifique o que seu app faz durante o upload

Muitos apps definem permissões automaticamente durante o upload, frequentemente copiando um tutorial. Procure no código por termos como "public-read", "acl", "make public" ou fallbacks que trocam URLs assinadas por URLs públicas quando algo falha.

Para validar o comportamento real, suba um arquivo de teste e verifique:

  • Pode ser lido sem login?
  • Aparece em algum endpoint de listagem?
  • Mudar defaults do bucket afeta objetos existentes?

Fique de olho na deriva entre dev, staging e produção

Times às vezes trancam produção, mas deixam dev ou staging abertos, então acidentalmente apontam o frontend ou app móvel para o bucket errado. Um modo comum de falha é um bucket de staging “temporário” com leitura global, mais uma build de release que ainda usa config de staging.

Audite suas regras de upload para que arquivos privados permaneçam privados

Find Exposure Before It Spreads
If a file opens in incognito, we can pinpoint why and patch the real cause.

A maioria dos vazamentos de storage começa no momento do upload. Se seu app permite que alguém envie um arquivo, você precisa de regras claras sobre quem pode enviar, onde o arquivo vai e quem pode lê-lo depois.

Exija autenticação antes de qualquer upload, ou use uploads assinados que expirarem rápido. Um upload assinado deve permitir um único objeto, em um único local, por um curto período, e apenas para o usuário logado que o solicitou.

Validação importa mesmo quando o storage é privado. Uploads inseguros ainda podem criar problemas de segurança e custos. Mantenha as regras simples:

  • Aceite somente os tipos que realmente precisa (verifique conteúdo, não só extensão).
  • Defina um limite de tamanho rígido.
  • Use paths por usuário e IDs aleatórios (não nomes de usuário ou timestamps).
  • Bloqueie sobrescritas a menos que “substituir este arquivo” seja uma funcionalidade intencional.

Um exemplo simples: uploads/jane/profile.jpg é fácil de adivinhar. uploads/user_123/9f3a2c... é muito mais difícil de adivinhar e mais fácil de controlar com políticas.

Pare com adivinhação, listagem e vazamento por metadados

Um bucket pode ser “privado” e ainda vazar dados se as pessoas puderem adivinhar chaves, listar objetos ou aprender demais por metadados.

Desative a listagem onde seu provedor permitir. A listagem transforma uma adivinhação sortuda em um diretório inteiro de arquivos de usuários.

Em seguida, corrija nomes previsíveis. Se arquivos são nomeados como users/[email protected]/avatar.png ou invoices/1042.pdf, terceiros podem brute-force e confirmar quais usuários existem. Use IDs aleatórias e não previsíveis para chaves de objeto e mantenha identificadores de usuário fora dos paths.

Metadados também podem vazar informações. Nomes originais frequentemente contêm nomes reais, nomes de projetos ou IDs de cliente. Alguns sistemas também armazenam metadados customizados como user_id ou account_tier, o que vira um problema se um objeto algum dia se tornar público por engano.

Se estiver reduzindo risco de descoberta, foque em três medidas: bloquear listagem, usar chaves não adivinháveis e manter metadados no mínimo.

Logs e alertas que realmente detectam exposição

Lock Down User Uploads
Turn a demo-ready prototype into private-by-default storage with verified access checks.

Muitos vazamentos de buckets são descobertos tardiamente, depois que arquivos já foram baixados por dias. Logs transformam uma auditoria pontual em proteção contínua.

Ative logs para leituras, gravações e deleções, não apenas para erros. Leituras importam mais, porque um bucket público pode ser raspado sem quebrar nada.

Uma entrada de log útil responde quatro perguntas:

  • Quem acessou (usuário, conta de serviço ou anônimo)
  • O que aconteceu (leitura, upload, deleção)
  • Qual objeto foi tocado (caminho/chave completa)
  • Quando aconteceu (timestamp)

Para alertas, foque em padrões que geralmente sinalizam problema: acesso anônimo e volume incomum. Uma única leitura anônima pode ser um teste de má-configuração. Um pico de leituras anônimas é frequentemente um scraper.

Mantenha alertas pequenos e acionáveis. Por exemplo: leituras anônimas em bucket privado, picos repentinos de downloads, ou muitos “not found” (sinal de adivinhação de chaves).

Decida também retenção com base em quanto tempo um incidente pode ficar despercebido. Se você só guarda sete dias, pode não conseguir provar o que foi acessado.

Correções que reduzem risco e permanecem simples

A maneira mais fácil de ficar seguro é escolher um modelo e mantê-lo: um bucket é para ativos públicos (logos, imagens de marketing) ou para arquivos privados de usuários (faturas, fotos de perfil, exports). Misturar ambos é onde “ops, ficou público” costuma acontecer.

Comece privado por padrão. Bloqueie acesso público no nível do bucket e só abra o que realmente precisa ser público. Se algo deve ser público, torne isso óbvio por design (bucket separado, nomeação clara), não por acidente.

Para downloads privados, evite URLs públicas permanentes. Sirva arquivos através do seu app após login e checagens de permissão, ou use URLs assinadas que expiram rápido. Exemplo: o usuário pede um PDF export, seu app verifica propriedade e emite um link que funciona por cinco minutos.

Escreva as regras finais (quem pode fazer upload, quem pode ler, o que é público). A maioria dos incidentes repetidos acontece quando alguém “conserta no console” mas o app continua fazendo upload com o comportamento antigo.

Cenário de exemplo: um app startup com uploads de usuário expostos

Uma pequena startup entrega rápido. Usuários podem enviar fotos de perfil e o app as armazena num bucket na nuvem. Tudo parece bem até um usuário postar uma captura de tela mostrando a foto de outra pessoa abrindo num navegador.

Como isso acontece: o bucket permite leituras públicas, ou uma ACL antiga public-read ainda está sendo aplicada no upload. O app também usa nomes previsíveis como user_123/avatar.jpg. Ninguém quis tornar as fotos públicas, mas defaults e escolhas de nomeação fizeram isso silenciosamente.

Uma vez que mesmo um arquivo é legível sem login, adivinhar fica fácil. Um atacante pode tentar IDs comuns (1, 2, 3...) e pedir avatar.jpg cada vez. Se a listagem estiver habilitada, pode nem precisar adivinhar.

Um plano prático de correção que você pode implementar em um dia:

  • Bloquear acesso público e remover ACLs públicas em objetos existentes.
  • Usar URLs assinadas de curta duração para downloads privados.
  • Mudar a nomeação para chaves não adivinháveis (IDs aleatórios) e evitar IDs de usuário em paths.
  • Aplicar regras de upload (tipo, tamanho, caminho de destino) e rejeitar sobrescritas não intencionais.
  • Revisar logs por picos incomuns de leitura e rotacionar quaisquer segredos expostos.

Erros comuns que causam buckets públicos acidentais

Human Verified Security Fixes
Our team verifies fixes by hand, not just automated scans.

A maioria dos buckets públicos não é fruto de um hacker. Acontecem porque uma escolha temporária vira permanente, ou porque ninguém é dono das configurações após o lançamento.

Uma armadilha comum é assumir que “não linkado” significa privado. Se um bucket permite leituras anônimas, um arquivo pode ser aberto por quem adivinhar o caminho. Se a listagem estiver ativada, o atacante nem precisa adivinhar.

Outro problema frequente é copiar configurações de desenvolvimento para produção. Buckets de dev costumam permitir amplo acesso para que a equipe trabalhe rápido. Quando esse template é reaplicado a dados reais de usuários, você acaba hospedando arquivos privados com regras de demo.

Erros que aparecem repetidamente:

  • Permitir que o navegador ou app cliente defina ACLs diretamente sem checagens estritas do servidor.
  • Usar URLs públicas permanentes para arquivos que deveriam ser privados.
  • Confiar em obscuridade (nomes aleatórios) em vez de controles de acesso.
  • Deixar buckets de teste antigos com dados reais de clientes.
  • Misturar arquivos públicos e privados no mesmo bucket e criar exceções que se espalham.

Próximos passos: trave e faça uma auditoria

Decida como “correto” deve ser para cada tipo de arquivo que você armazena. Avatares e imagens de marketing podem ser públicos por design. Recibos, exports, uploads de chat e qualquer coisa ligada a conta de usuário devem ser privados por padrão, com acesso concedido apenas pelo seu app.

Uma vez que tiver esse comportamento alvo, verifique configurações de bucket e depois verifique os caminhos de código que fazem upload, leitura e compartilhamento de arquivos. Buckets raramente vazam sozinhos. A maioria dos vazamentos acontece porque o app define a ACL errada, gera uma chave adivinhável ou grava uploads em um caminho público.

Um jeito prático de travar sem complicar:

  • Faça uma tabela simples: tipo de arquivo, público ou privado e quem pode acessar.
  • Audite configurações e políticas do bucket contra essa tabela.
  • Reveja o código de upload: caminho de destino, permissões definidas no upload e flags de “tornar público”.
  • Adicione um teste de regressão pós-deploy: tente listar o bucket e buscar um arquivo que você não deveria acessar.
  • Ative logs e alertas para mudanças de política e picos de leituras anônimas.

Se você herdou um protótipo gerado por IA (por exemplo, vindo de Lovable, Bolt, v0, Cursor ou Replit), permissões de storage e caminhos de upload são frequentemente onde o “funcionou na demo” vira um incidente real de privacidade. Se quiser ajuda para desenrolar isso, FixMyMess (fixmymess.ai) pode rodar uma auditoria de código gratuita para identificar buckets expostos, checagens de acesso quebradas e defaults de upload arriscados, e então verificar as correções com revisão humana.

Perguntas Frequentes

How can I quickly tell if my bucket is exposed?

Abra a URL real de um arquivo em uma janela privada/incógnita. Se ele carregar sem fazer login, trate-o como público.

Também tente acessar um arquivo que você NÃO deveria ver (por exemplo, o avatar ou a fatura de outro usuário) usando o mesmo padrão de URL. Se conseguir buscá-lo, seus controles de acesso não estão funcionando.

Why is bucket listing worse than a single public file?

A listagem permite que alguém navegue por muitos objetos, não apenas busque um único arquivo adivinhado. Isso transforma um erro isolado em um despejo completo de dados.

Mesmo que só uma pequena parte seja listável, ela frequentemente revela nomes de arquivos, prefixos e padrões que tornam a adivinhação dirigida muito mais fácil.

What does “unlisted but guessable” actually mean?

Se seus URLs seguem padrões previsíveis como IDs de usuário, emails, timestamps ou números de pedido, terceiros podem forçar caminhos prováveis. Isso faz com que “não listado” seja, na prática, público.

A correção é usar chaves de objeto não adivinháveis e aplicar verificações de acesso para cada leitura, não apenas ocultar o link.

What’s the difference between a bucket policy and object ACLs?

As políticas de bucket são regras amplas que podem permitir (ou bloquear) leitura e listagem em muitos objetos. As ACLs de objeto são permissões por arquivo e podem, silenciosamente, tornar uploads individuais públicos mesmo quando o bucket parece protegido.

É preciso verificar ambos, porque uma ACL permissiva num upload de usuário pode vazar arquivos privados sem alterar a política principal do bucket.

How do I make an inventory of buckets without missing the “forgotten” ones?

Faça um inventário simples de cada bucket e do que ele armazena, incluindo exports esquecidos, backups e projetos antigos de staging. Depois mapeie cada bucket ou prefixo para a funcionalidade do app que grava nele.

Quando souber o que pertence a cada lugar, você pode decidir o que deve ser público, o que deve ser privado e quais caminhos nunca devem ser acessíveis sem autenticação.

How do staging and dev buckets end up leaking production data?

Muitas equipes trancam produção, mas deixam dev ou staging abertos e depois acidentalmente usam esse bucket aberto em uma build. Outro deslize comum é copiar um template “amigo do demo” para um ambiente real.

Verifique a configuração do app para saber qual bucket é usado em cada ambiente e confirme que dev/staging não contêm dados reais de clientes.

What are the safest upload rules for private user files?

Um padrão seguro é: exigir autenticação antes do upload e usar uploads assinados de curta duração que permitam um único objeto, em um único caminho, para um único usuário. Depois do upload, mantenha objetos privados e sirva downloads somente após verificações de permissão.

Se for usar uploads diretos para o storage, garanta que o servidor — não o cliente — decida o caminho final e as permissões.

How should we name files so people can’t guess URLs?

Use chaves de objeto randomizadas e não adivinháveis e evite colocar identificadores de usuário em paths. Por exemplo, não use emails, IDs sequenciais, números de fatura ou timestamps como chave principal.

Também monitore nomes de arquivo originais e metadata personalizada. Se algo se tornar público por engano, nomes e metadados podem vazar mais informações do que o conteúdo do arquivo.

What logging and alerts help catch bucket exposure early?

Ative logs para leituras, gravações e deleções, não apenas para erros — leituras importam porque um bucket público pode ser raspado sem quebrar nada.

Os sinais mais úteis são: acessos anônimos, picos repentinos de downloads e muitos 404s (indicando adivinhação). Mantenha alertas pequenos e acionáveis e retenha logs tempo suficiente para investigar incidentes que passem despercebidos.

What should I do first if I discover public access on a bucket?

Tranque o acesso público imediatamente: bloqueie o acesso público no nível do bucket, remova ACLs públicas e confirme que a listagem está desativada. Depois, verifique se o código de upload do seu app não está recriando objetos públicos nos uploads novos.

Se você herdou um protótipo gerado por IA, defaults de storage e caminhos de upload costumam ser a origem da exposição. FixMyMess (fixmymess.ai) pode executar uma auditoria de código gratuita para encontrar as más configurações exatas e confirmar as correções com revisão humana.