← Guias por stack

Bolt

Segurança para a tua app Bolt

O Bolt.new cria uma app full-stack no browser e publica-a com um clique, mas essa rapidez esconde decisões de segurança: chaves que colas no chat e acabam no frontend, zero headers e uma SPA que a IA não consegue ver. Analisa a tua app e fica a saber ao certo em 30 segundos.

Riscos típicos em Bolt

Chaves coladas no chat que acabam no frontend

Para "ligar" um serviço colas a chave no Bolt, e muitas vezes ele acaba por a integrar no código do cliente. Tudo o que chega ao browser é público: essa chave fica à vista de todos.

Deploy sem headers de segurança

O deploy do Bolt serve a tua app por HTTPS, mas sem CSP, HSTS ou X-Frame-Options. Estes headers não estão lá por defeito e têm de ser acrescentados no alojamento.

SPA invisível para motores de busca e IA

O Bolt gera SPAs cujo conteúdo só aparece depois de o JavaScript correr. Os crawlers de IA e alguns motores de busca veem uma página quase vazia e não te conseguem indexar nem citar.

"Segurança no Bolt" são duas coisas que convém separar. A primeira é o projeto do Bolt em si: o que colas no chat, onde acabam as variáveis de ambiente, com quem partilhas o projeto e para onde é feito o deploy. A segunda é o código que o Bolt gera, quase sempre uma SPA com Vite e React ligada ao Supabase, que traz as mesmas cinco ou seis falhas de sempre. Este guia cobre as duas, com um ficheiro de instruções para que o Bolt aplique as regras em cada geração, um prompt de revisão antes do deploy e a forma de verificar o resultado de fora.

Parte 1: proteger o teu projeto do Bolt

O Bolt corre no teu navegador, e isso muda onde vivem as chaves

O Bolt executa o projeto inteiro dentro do navegador com WebContainers. Não há servidor próprio enquanto desenvolves, por isso qualquer chave que ponhas num ficheiro .env está no projeto, e se tiver o prefixo VITE_ acaba embutida no bundle que é publicado. Para o navegador isso só é correto com chaves públicas (a anon do Supabase, a publishable do Stripe). As secretas não têm lugar no frontend: vão para uma Edge Function do Supabase ou uma função da Netlify, e o cliente chama a função.

O que colas no chat acaba no código

Se colas uma chave na conversa para "ligar" um serviço, o modelo escreve-a onde precisa dela, que normalmente é um componente. A partir daí viaja para todos os visitantes. A regra: as chaves públicas vão no .env; as secretas, no painel do serviço que executa a função (Supabase ou Netlify), nunca no chat. E se colaste uma por engano, roda-a: o histórico conserva-a mesmo que a apagues do código.

Partilhar, exportar e fazer deploy

Um link de projeto partilhado mostra o código completo, incluindo o .env. Antes de partilhar, revê o que está lá dentro. Se exportas para o GitHub, que o repositório seja privado e que o .env esteja no .gitignore. O deploy com um clique vai para a Netlify, num subdomínio .netlify.app ou no teu domínio; a Netlify dá TLS e redirecionamento para HTTPS, mas não cabeçalhos de segurança, e as variáveis de ambiente de produção configuram-se no painel dela, não no .env do projeto.

O Supabase é teu

A integração do Supabase cria tabelas, políticas e funções a partir do chat. RLS, buckets e definições de Auth continuam a ser responsabilidade tua, e o Bolt comete os mesmos erros que o Lovable com as políticas. O guia de segurança para Supabase tem três consultas SQL para auditar o projeto num minuto.

Parte 2: as falhas que o Bolt mete no teu código

  • Chaves secretas em componentes. Uma chamada à OpenAI ou ao Stripe a partir do React com a chave lá dentro. Procura sk_, service_role e Bearer no teu bundle publicado.
  • Tabelas sem RLS ou com políticas using (true). Quando uma consulta falha por permissões, o modelo abre a política em vez de a corrigir.
  • Edge Functions sem autenticação. O template responde a qualquer pessoa com Access-Control-Allow-Origin: *; se a função gasta dinheiro, qualquer pessoa o pode gastar.
  • Verificações só na interface. A página de administração esconde-se se não fores administrador, mas a API responde na mesma.
  • Source maps em produção. Alguns templates de Vite trazem build.sourcemap: true; publica o teu código original ao lado do minificado.
  • Invisível para a IA e os motores de busca. O HTML chega vazio e os bots do ChatGPT ou do Perplexity não veem nada. Se a landing importa, pré-renderiza-a ou separa-a. Detalhe em porque é que as apps feitas com IA são invisíveis para a IA.
  • Sem cabeçalhos de segurança. Nem CSP, nem HSTS, nem X-Frame-Options. Na Netlify acrescentam-se com um ficheiro.

Um bloco para o Bolt aplicar sempre

O Bolt lê o ficheiro .bolt/prompt do teu projeto como instruções permanentes. Cria o ficheiro e cola isto:

Regras de segurança deste projeto:
- Nunca ponhas chaves secretas no código do frontend nem em variáveis VITE_. As integrações com chaves secretas vão numa Edge Function do Supabase ou numa função da Netlify que lê a chave das suas variáveis de ambiente.
- Toda a tabela nova tem RLS ativado e uma política explícita por operação. Não uses using (true) nem with check (true) exceto em conteúdo público só de leitura, e avisa-me quando o fizeres.
- Toda a função de servidor verifica o JWT do utilizador, limita Access-Control-Allow-Origin ao nosso domínio e valida a entrada.
- As permissões de administrador verificam-se no RLS ou no servidor, nunca só na interface.
- Os ficheiros de utilizadores vão para buckets privados com políticas e URLs assinados.
- build.sourcemap fica desativado em produção.
- Põe título, meta descrição e etiquetas Open Graph reais no index.html.

E os cabeçalhos para a Netlify, num ficheiro public/_headers que é publicado com a app:

/*
  Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
  X-Content-Type-Options: nosniff
  X-Frame-Options: DENY
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=(), geolocation=()

Um prompt de revisão antes do deploy

Revê a segurança deste projeto e não mudes nada ainda. Responde com uma lista:
1. Chaves ou tokens no código do frontend ou em variáveis VITE_, com ficheiro e linha.
2. Tabelas sem RLS e políticas com using (true) ou with check (true).
3. Funções de servidor que não verifiquem o JWT, que respondam com Access-Control-Allow-Origin: * ou que não validem a entrada.
4. Ações de administrador protegidas só na interface.
5. Buckets públicos com ficheiros de utilizadores.
6. build.sourcemap ativado e ausência do ficheiro _headers.
7. Metadados do index.html que continuem a ser os do template.
Para cada ponto, propõe a alteração exata e espera pela minha confirmação.

Verifica o resultado de fora

curl -sI https://oteudominio.com | grep -iE "strict-transport|x-frame|x-content-type"
curl -s https://oteudominio.com | grep -oE '/assets/[^"]+\.js' | head -1
curl -s https://oteudominio.com/assets/index-XXXX.js | grep -oE "sk_live_[A-Za-z0-9]+|service_role|eyJhbGciOi[A-Za-z0-9_-]{20,}" | head -3
curl -sI https://oteudominio.com/assets/index-XXXX.js.map | head -1

O esperado: cabeçalhos presentes, nenhuma chave no chunk e um 404 no source map. Depois testa a API do Supabase sem sessão como explica o guia do Supabase. O Scanaris faz estas verificações e cerca de quarenta mais em 30 segundos: deteta que a app é do Bolt, procura segredos no bundle, verifica source maps, cabeçalhos, CORS, cookies e ficheiros expostos, testa as tabelas do Supabase sem sessão e revê se o teu conteúdo é legível sem JavaScript. Por cada falha dá-te um fix prompt para colar no chat do Bolt, e pode voltar a analisar todos os dias, porque uma regeneração pode trazer de volta uma falha corrigida.

Perguntas frequentes

As variáveis VITE_ são privadas?

Não. O Vite embute no bundle tudo o que comece por VITE_; é a forma dele de dizer "isto é público". As chaves secretas não levam esse prefixo e não se leem a partir do frontend.

Posso pôr cabeçalhos de segurança na Netlify?

Sim, com o ficheiro _headers na pasta pública ou com o netlify.toml. A Netlify aplica-os no deploy seguinte; confirma com curl.

O que faço se colei uma chave secreta no chat do Bolt?

Roda-a no serviço de origem mesmo que a tenhas apagado do código: o histórico do projeto e os deploys anteriores conservam-na. Depois acrescenta-a no painel do Supabase ou da Netlify e pede ao Bolt que mova a integração para uma função.

Verificações relacionadas

A tua app Bolt passa nestas verificações?

Analisa-a grátis e recebe um fix prompt por cada problema que encontrarmos.

Analisar o meu site grátis