Guia geral · Segurança
Como garantir a segurança de apps criados com vibe coding?
Apps criados com ferramentas de vibe coding — Lovable, Bolt, Cursor, v0 — não são seguros por padrão. Essas plataformas priorizam velocidade de entrega e raramente seguem boas práticas de segurança no código gerado. Nos apps vibe-coded escaneados pelo Defenty, os problemas mais frequentes são API keys expostas no JavaScript do frontend, banco de dados Supabase sem Row Level Security e endpoints que aceitam operações sem verificar autenticação. A boa notícia é que a maioria desses problemas é corrigível em poucas horas — desde que você os encontre antes de alguém mal-intencionado.
O que é vibe coding e por que a segurança vira problema
Vibe coding é o processo de construir aplicações inteiras descrevendo o que você quer em linguagem natural — e deixando uma IA gerar o código. Ferramentas como Lovable, Bolt, v0 e o modo Composer do Cursor fazem exatamente isso: transformam uma ideia em um app funcional em minutos, com banco de dados, autenticação e deploy configurados automaticamente.
O problema estrutural é que modelos de linguagem são treinados para gerar código que funciona, não código que é seguro. O corpus de treinamento inclui tutoriais que colocam chaves de API diretamente no código, exemplos do Stack Overflow que omitem autenticação "para simplificar" e repositórios com variáveis de ambiente hardcoded. Quando você pede ao modelo para "fazer funcionar", ele segue esses padrões sem questionar se são seguros para produção.
As 5 falhas de segurança mais comuns em apps vibe-coded
1. API keys expostas no bundle JavaScript
Quando você usa o prefixo NEXT_PUBLIC_ no Next.js — ou VITE_ no Vite — a variável de ambiente é embutida diretamente no JavaScript que o navegador baixa. Isso é por design: essas variáveis são intencionalmente públicas. O problema é que ferramentas de vibe coding frequentemente geram código usando esses prefixos para chaves que deveriam ser privadas.
O caso mais crítico é a SUPABASE_SERVICE_ROLE_KEY com prefixo NEXT_PUBLIC_. Essa chave tem acesso administrativo ao banco — ignora completamente o Row Level Security, pode criar e deletar usuários, ler qualquer tabela. Exposta no frontend, ela entrega controle total do seu banco a qualquer pessoa que inspecionar o código-fonte.
Chaves da OpenAI expostas geram um risco diferente: não expõem seus dados, mas permitem que outros usem sua cota — e sua fatura. Casos documentados em comunidades de desenvolvedores relatam cobranças de US$ 4.000 a US$ 8.000 acumuladas em um único fim de semana após exposição de chave.
Como detectar
Abra o DevTools (F12 → Sources) e pesquise por NEXT_PUBLIC_, sk-, eyJ (prefixo de JWT). Ou no terminal, após um build local: grep -r "sk-" .next/static/
2. Row Level Security (RLS) desabilitado no Supabase
O Supabase é o banco de dados mais usado em projetos vibe-coded — Lovable o integra automaticamente, Bolt o sugere como padrão. Ele expõe duas credenciais no dashboard: a anon key e a service_role key. A chave anon é considerada pública e aparece no frontend — isso é correto por design. O que não é correto é deixar o banco sem RLS.
Sem RLS ativo, qualquer pessoa com a URL do projeto Supabase e a chave anon — ambas encontradas no bundle JavaScript — pode executar SELECT * FROM users e obter todos os registros da tabela. Pode inserir dados, atualizar registros de outros usuários, deletar linhas. Toda a tabela fica acessível como se fosse uma API pública sem senha.
O RLS não vem ativo por padrão em novas tabelas — você precisa ativar explicitamente. Ferramentas de vibe coding raramente fazem isso, porque a documentação do Supabase apresenta o RLS como um passo opcional de "segurança avançada", não como requisito básico.
Como detectar
No Supabase Dashboard → Table Editor: cada tabela mostra um ícone de cadeado. Cadeado aberto = RLS desativado. Ou execute no SQL Editor: SELECT tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public';
3. Endpoints de API sem verificação de autenticação
O padrão mais perigoso é um endpoint que aceita userId no body da requisição e opera sobre esse ID sem verificar se quem está chamando tem permissão. Isso é um IDOR — Insecure Direct Object Reference. Um atacante pode passar o ID de qualquer outro usuário e sobrescrever seus dados, deletar seu cadastro ou ler suas informações privadas.
Um segundo padrão: rotas administrativas como /api/admin/export-users ou /api/delete-all-sessions criadas "só para uso interno" mas sem qualquer camada de proteção. Ferramentas automatizadas de reconhecimento testam centenas de rotas comuns por minuto.
Como corrigir
// ❌ Endpoint aberto — qualquer pessoa pode chamar
export async function POST(request: Request) {
const { userId, data } = await request.json();
await db.update(userId, data); // userId vem do atacante
return Response.json({ ok: true });
}// ✅ Verifica sessão antes de qualquer operação
import { getServerSession } from 'next-auth';
export async function POST(request: Request) {
const session = await getServerSession();
if (!session) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
const { data } = await request.json();
await db.update(session.user.id, data); // ID vem da sessão, não do body
return Response.json({ ok: true });
}4. Secrets no histórico do repositório Git
Git mantém histórico completo de todos os arquivos commitados, incluindo os que foram deletados depois. Se um arquivo .env foi commitado — mesmo que por acidente, mesmo que por um segundo — ele está recuperável com git show. Deletar o arquivo e fazer um novo commit não resolve: o histórico permanece.
Repositórios públicos no GitHub são indexados por bots especializados em segundos após um push. O GitHub Secret Scanning detecta alguns padrões conhecidos, mas chaves customizadas ou formatos não mapeados passam sem alerta. Considere que qualquer chave que chegou a um repositório público já foi capturada.
Se você descobriu que commitou uma chave: revogue primeiro, reescreva o histórico depois. A ordem importa — reescrever o histórico leva minutos, tempo suficiente para o bot capturar a chave se ela ainda estiver ativa.
Como detectar e remover
# Verificar se .env foi commitado em algum momento git log --all --full-history -- .env .env.local .env.production # Buscar padrões de chaves no histórico completo git grep -l "sk-" $(git log --pretty=format:"%H") # Se encontrar: revogar a chave IMEDIATAMENTE no painel do serviço # Depois remover do histórico (não basta deletar o arquivo): pip install git-filter-repo git filter-repo --path .env --invert-paths
5. CORS permissivo demais
Configurar Access-Control-Allow-Origin: * é o atalho padrão para resolver erros de CORS durante o desenvolvimento. O problema é que frequentemente vai para produção assim. Com CORS aberto para qualquer origem, um site malicioso pode fazer requisições autenticadas à sua API utilizando os cookies de sessão de um usuário logado no seu app — sem que o usuário perceba.
O ataque funciona assim: o usuário está logado no seu app, visita outro site, esse site executa um fetch para seuapp.com/api/transferir-dados com credentials: 'include'. O navegador inclui os cookies automaticamente. Com CORS permissivo, a operação executa com os privilégios do usuário logado.
Como corrigir
// ❌ Permite qualquer origem — habilita ataques CSRF
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
};// ✅ Lista explícita de origens permitidas
const ALLOWED_ORIGINS = [
'https://meuapp.com',
'https://www.meuapp.com',
];
export function getCorsHeaders(request: Request) {
const origin = request.headers.get('origin') ?? '';
const allowed = ALLOWED_ORIGINS.includes(origin) ? origin : ALLOWED_ORIGINS[0];
return {
'Access-Control-Allow-Origin': allowed,
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
'Vary': 'Origin',
};
}Como um finding real do Defenty aparece
Abaixo um exemplo de achado crítico retornado pelo Defenty ao detectar uma API key exposta no JavaScript público de um app. O campo evidence mostra o início do token — suficiente para confirmar o tipo de credencial sem expor o valor completo no relatório.
{
"severity": "critical",
"type": "exposed_secret",
"title": "API Key exposed in JavaScript bundle",
"detail": "Found SUPABASE_SERVICE_ROLE_KEY in chunk-abc123.js",
"evidence": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"impact": "Full database read/write access without authentication",
"remediation": "Move to server-side environment variable — NEXT_PUBLIC_ prefix bypasses protection"
}Por que isso acontece — sem jargão
Imagine que você contratou um pedreiro para construir uma casa rapidamente. Ele entrega a obra no prazo — paredes, telhado, janelas. Mas as fechaduras são decorativas, a janela dos fundos não trava e o cofre está no jardim sem tampa. Funcionalmente, é uma casa. Do ponto de vista de segurança, é um risco.
Ferramentas de vibe coding fazem algo parecido: entregam um app funcional com velocidade impressionante, mas as decisões de segurança — onde guardar chaves, quem pode acessar o quê, o que validar — precisam vir de você. A IA não sabe que seu app vai receber dados de clientes reais, processar pagamentos ou armazenar informações sensíveis. Você sabe. E essa responsabilidade não é transferível para a ferramenta.
Como identificar os problemas no seu app agora
- 1
Inspecione o bundle JavaScript
Abra o DevTools (F12 → Sources) e pesquise por "key", "token", "secret", "password", "sk-", "eyJ". Qualquer chave de serviço encontrada aqui é um achado crítico.
- 2
Verifique o RLS no Supabase
No Supabase Dashboard, vá em Table Editor e confirme que o cadeado ao lado de cada tabela está fechado. Cadeado aberto = dados expostos publicamente.
- 3
Teste endpoints sem autenticação
Abra uma aba anônima e use o console para chamar diretamente as rotas da sua API que modificam dados. Se funcionar sem estar logado, é uma falha.
- 4
Verifique o histórico do Git
Execute `git log --all --full-history -- .env*` para verificar se arquivos de configuração foram commitados em algum momento, mesmo que já tenham sido removidos.
- 5
Use um scanner automatizado
Um scanner de segurança faz esse processo de forma sistemática e encontra padrões que a inspeção manual perde — como chaves parcialmente ofuscadas, rotas não documentadas e headers de segurança ausentes.
Veja se seu app tem algum desses problemas
O QuickScan do Defenty verifica API keys expostas, headers de segurança, SSL, tecnologias vulneráveis e mais — em minutos, sem cadastro.
Escanear meu app agora — grátisSem cadastro · Resultado por e-mail em minutos