Pular para o conteúdo

Seu app do v0 é seguro?

É seguro construir com o v0? Os componentes gerados não são o risco. O risco é a ligação que você monta em volta, e um nome de variável decide quase tudo.

Vlad Tkachenko5 min de leitura
O cartão de verificação de segurança da Reeve para apps do v0, com o logo do v0 num ladrilho branco.

Os logotipos são propriedade de seus respectivos donos e são exibidos apenas para indicar compatibilidade.

Em resumo

  • Um app do v0 costuma dar para publicar sem medo; os componentes gerados não são o risco. O risco é a ligação que você monta em volta.
  • Qualquer variável chamada NEXT_PUBLIC_… é compilada no JavaScript que os seus visitantes baixam. Isso está certo para uma chave publicável e errado para uma secreta.
  • O v0 não define as regras do seu banco. No Supabase, tabelas criadas rodando SQL começam sem Row Level Security.

O v0 te dá componentes: uma interface funcionando, gerada e colocada dentro do seu projeto. O que ele não te dá é a ligação por trás: as variáveis de ambiente, o banco de dados, as regras sobre quem pode ler o quê. É nessa lacuna que um projeto do v0 costuma dar errado, e ele dá errado em silêncio.

Aqui está o que guia após guia erra: o código gerado não é o risco. O risco é uma convenção de nomes no seu arquivo de ambiente e uma configuração de banco que não tem nada a ver com o v0.

Qual metade de um projeto do v0 é pública

A metade da interface, inteira.

Pense numa loja. Os componentes que o v0 escreve são a vitrine: cada página, cada formulário, cada botão, e a vitrine inteira é entregue a cada visitante que carrega o seu site. Não tem como escapar disso: um navegador não desenha uma página que não recebeu. Atrás dela fica o estoque, o seu banco de dados, um prédio separado com a própria fechadura.

O que torna um projeto do v0 diferente é que quem junta as duas metades é você. Os componentes chegam sem saber nada das suas chaves nem das suas tabelas, então toda decisão sobre o que atravessa do estoque para a vitrine é sua, tomada dentro do seu projeto, normalmente num único arquivo cheio de variáveis de ambiente.

O que NEXT_PUBLIC_ realmente quer dizer

Quer dizer "coloque isto no navegador".

O Next.js, que é para o que o v0 gera código, decide o que os seus visitantes recebem lendo o nome da variável. Tudo que se chame NEXT_PUBLIC_ALGUMA_COISA é compilado no JavaScript que o seu site entrega. Tudo sem esse prefixo fica no servidor. A mesma regra existe com outros nomes em outras ferramentas: o Vite usa o prefixo VITE_ e diz claramente que esses valores vão empacotados no seu código-fonte na hora do build, mas o efeito é idêntico: o prefixo publica o valor.

Isso é exatamente o certo para uma URL de projeto ou uma chave publicável. E exatamente o errado para uma secreta.

As duas se chamam chave de API. Só uma delas foi feita para ser lida.

A armadilha tem um formato reconhecível. Alguma coisa na interface não consegue ler um valor, então o prefixo é acrescentado para o erro sumir, e ele some, e o app começa a funcionar. Se o valor era uma chave sb_publishable_… do Supabase, ou a antiga chave anon, não há problema. Se era sb_secret_… ou service_role, o erro era o sistema te dizendo que aquele código pertence a um servidor, e a renomeação publicou uma chave que ignora todas as regras que você definiu. Diferenciar as duas leva cerca de um minuto e vale fazer uma vez para cada chave do arquivo.

O que decide se estranhos conseguem ler os seus dados

As regras do seu banco de dados, não os seus componentes.

O seu app e um estranho batem na mesma porta. A configuração decide quem entra, não as telas do seu app.

Se os seus dados estão no Supabase, a configuração é o Row Level Security: uma chave por tabela que decide linha a linha quem pode ler o quê. Com ela desligada, a sua chave publicável devolve a tabela inteira para quem pedir. Com ela ligada e uma política escrita, devolve só o que a política permite.

O Supabase liga isso por padrão nas tabelas criadas no Table Editor do painel e não nas criadas rodando SQL. Então as tabelas que você fez nascer clicando costumam estar protegidas, e qualquer tabela criada por um arquivo de migração talvez não esteja. Depois as duas parecem iguais, e as duas funcionam.

Existe uma segunda versão disso que pega quem fez tudo certo: uma tabela pode estar com Row Level Security ligado e mesmo assim aberta para todo mundo, por causa da política nela. Ligado e protegido são dois estados diferentes.

Como conferir o seu próprio projeto do v0 em uns dez minutos

Leia o seu arquivo de ambiente linha a linha. Toda variável com o prefixo NEXT_PUBLIC_ está publicada. Pergunte-se a cada uma: eu ficaria tranquilo imprimindo isto na página inicial? Se não, ela não pertence a esse prefixo.

Troque qualquer coisa que nunca deveria estar ali. No painel do seu provedor, gere uma chave nova e revogue a antiga. Tirar a linha do seu código não fecha a porta, porque o valor antigo continua no seu histórico de versões e em cópias em cache do site.

Confira as regras das suas tabelas. No Supabase, Authentication → Policies lista cada tabela e se o Row Level Security está ligado. Tudo que estiver desligado pode ser lido por qualquer um que tenha o endereço do seu projeto.

E então olhe de fora. Os passos acima dizem o que está configurado; eles não dizem o que é de fato alcançável. O nosso scan gratuito lê o seu site no ar do jeito que um visitante leria e te dá uma nota em uns 20 segundos, sem conta: escaneie seu app.

O que fazer

  • NEXT_PUBLIC_ não é formalidade. Ele compila o valor dentro dos arquivos que cada visitante baixa.
  • Acrescentar o prefixo para calar um erro é a hora de parar e conferir o que o valor realmente é.
  • Uma chave publicável pertence ao navegador. sb_secret_… e service_role nunca.
  • O v0 não define as regras do seu banco. No Supabase, tabelas criadas rodando SQL começam sem Row Level Security.
  • Uma tabela com Row Level Security ligado ainda pode estar aberta para todo mundo. A política é a parte que decide.

Abra o seu arquivo de ambiente e leia as linhas NEXT_PUBLIC_ em voz alta. Se alguma guarda algo que você não imprimiria na sua página inicial, troque a chave agora, e depois o checklist de segurança de 10 minutos cobre o que mais vale desligar num projeto recém-lançado.

O que pode dar errado de verdade com um app do v0

Nada disso é culpa sua: são os efeitos colaterais normais de gerar código rápido. Aqui está o que vale a conferida:

  • Uma chave secreta em um componente cliente (a armadilha NEXT_PUBLIC_)

    O v0 constrói com Next.js, que tem uma regra que faz as pessoas tropeçarem: qualquer coisa nomeada NEXT_PUBLIC_, e qualquer chave escrita direto em um componente cliente, é enviada ao navegador, onde qualquer um pode ler. É fácil colar uma chave de API em um componente gerado sem perceber que agora ela é pública. Algumas chaves devem ser públicas; o Reeve as distingue das que não devem, então sem alarmes falsos.

  • Seu banco de dados deixado aberto (RLS do Supabase desligado)

    Se o seu app do v0 guarda dados (muitas vezes no Supabase), há uma chave chamada Row Level Security (RLS) que decide quem pode ler ou alterar cada linha. Se estiver desligada, suas tabelas podem ficar abertas para qualquer um que encontrar o endereço. É o problema sério mais comum em apps gerados e permanece invisível até você olhar.

  • Source maps publicados

    Um “source map” revela o código original do seu app para qualquer um que abra as ferramentas do navegador. É útil durante o desenvolvimento, mas se for para produção entrega a estranhos uma cópia legível de como o seu app funciona, e deixa cada outra brecha mais fácil de achar. O Reeve verifica se os seus estão expostos.

  • Rotas de API abertas

    Apps Next.js costumam incluir rotas de API: pequenos endpoints que fazem coisas como ler ou gravar dados. Se uma foi gerada sem verificação de autenticação, ela pode responder a qualquer um que a chamar. O Reeve sonda se os seus endpoints respondem a estranhos, sem nunca usá-los para mudar nada.

  • Um arquivo .env ou de configuração exposto

    O arquivo .env guarda as chaves de um projeto. Ocasionalmente é publicado por engano com o app implantado, e se estiver acessível é um atalho para tudo o que é sensível. O Reeve verifica se o seu está acessível sem você saber.

  • Cabeçalhos de segurança ausentes e compartilhamento aberto (CORS)

    Pequenas configurações que dizem aos navegadores como proteger os visitantes, e se qualquer site pode chamar os dados do seu app. Pequenos sozinhos; juntos, ampliam a brecha. O Reeve sinaliza o que está faltando.

O que o Reeve é, e o que não é

O Reeve é uma verificação gratuita, somente leitura e por fora, como um inspetor que testa as portas sem entrar. É rápida e pega os erros comuns de grande impacto. Não é uma auditoria de segurança completa, e uma nota limpa não é garantia. Significa que as portas óbvias estão fechadas.

O v0 e a Vercel seguem elevando a qualidade do que é gerado e implantado, e se você usa Supabase, o próprio consultor dele sinaliza problemas de banco de dados no painel. Ambos ajudam. O que o Reeve acrescenta: você trabalha no v0, não lê o código gerado linha por linha, e essas ferramentas falam em linguagem de desenvolvedor. O Reeve olha o app implantado inteiro por fora e diz o que encontra em palavras simples. E se você preferir não pensar nisso, podemos monitorar para você.

Quer que seja resolvido, não só verificado?

O Reeve Care continua monitorando seu app, faz backup dos seus dados e ajuda você a corrigir as coisas quando quebram, para que você siga criando em vez de se preocupar.

Conheça o Reeve Care

Perguntas frequentes

O código do v0 está pronto para produção e é seguro?

O v0 produz código limpo e moderno, mas “parece pronto para produção” não é o mesmo que “verificado”. A segurança depende de como o app está ligado: onde as chaves ficam, se as regras do seu banco de dados estão ligadas, se os endpoints estão protegidos. O Reeve verifica as partes expostas de graça em cerca de 20 segundos.

Um app do v0 pode expor minhas chaves de API?

Sim, se uma chave acabar em um componente cliente ou em uma configuração NEXT_PUBLIC_, o Next.js envia essas ao navegador. Nem toda chave é um problema: algumas devem ser públicas. O Reeve encontra as chaves no seu código carregado e diz quais são seguras e quais precisam ir para o servidor.

As rotas de API do v0 são seguras?

Podem ser, mas um endpoint gerado às vezes sai sem verificação de autenticação, o que significa que qualquer um que o encontrar pode chamá-lo. O Reeve testa se os seus endpoints respondem a estranhos; ele só verifica se a porta abre, nunca a atravessa.

Verificar meu app do v0 vai quebrar algo?

Não. O Reeve só olha o que já é público por fora. Ele nunca faz login, nunca muda nada e nunca baixa dados. Somente leitura, como conferir se uma porta está trancada sem entrar.

O que o prefixo NEXT_PUBLIC_ faz de verdade?

Ele diz ao Next.js para compilar aquele valor dentro do JavaScript enviado ao navegador. O valor deixa de ser uma configuração de servidor e passa a fazer parte dos seus arquivos publicados, legível por qualquer visitante. Isso está certo para uma chave publicável e errado para uma secreta, e o prefixo é a única coisa que decide.

Renomeei uma variável para colocar NEXT_PUBLIC_ porque o app não conseguia ler. Foi um erro?

Depende inteiramente do que a variável guarda. Se era uma chave publicável ou uma URL de projeto, a renomeação foi a correção certa. Se era uma chave secreta, o app não conseguia ler porque ela nunca foi feita para rodar no navegador, e a renomeação publicou a chave. Troque essa chave e depois mova o código que precisava dela para uma rota de servidor.

O v0 configura as regras do meu banco de dados por mim?

Sozinho não. O v0 gera código de interface; o banco e as regras dele são você que monta, onde quer que os hospede. Se você está no Supabase, o Row Level Security vem ligado por padrão só nas tabelas criadas no Table Editor do painel, e desligado nas criadas rodando SQL.

Escrito por

Vlad Tkachenko

Fundador da Reeve

Passo meus dias olhando apps criados com Lovable, Bolt, v0, Cursor e Replit, e a curta lista de erros que aparecem neles sem parar.

Mais sobre o autor

Criou em outro lugar? Temos o mesmo resumo honesto para:

← Ver todos os guias de segurança dos criadores

Verificação externa automatizada, não uma auditoria completa. A ausência de achados não é garantia de segurança.