Você criou seu projeto no Lovable, fez deploy na Vercel, usou o Claude Code pra refatorar e o Copilot pra completar o código. Tudo funcionando, URL no ar, clientes acessando. Parabéns!
Agora a pergunta que pode salvar seu projeto: seu repositório está público no GitHub? Se sim, qualquer pessoa na internet pode ver seu código-fonte, suas chaves de API e toda a estrutura do seu banco de dados. Neste tutorial, vamos cobrir plataforma por plataforma o que cada uma faz de errado e como corrigir.
Por Que Isso É Tão Grave?
Quando você usa plataformas de Vibe Coding, o fluxo é mais ou menos assim:
- Você descreve o que quer (um SaaS, um dashboard, uma landing page)
- A IA gera código em React, Next.js, TypeScript
- A plataforma conecta com GitHub + Vercel e faz deploy automático
- Você recebe uma URL pública em minutos
O problema: nesse fluxo, nenhuma dessas plataformas configura segurança por padrão. O repositório fica público, as chaves ficam no código, e o deploy acontece sem nenhuma revisão.
🔴 O Erro Mais Perigoso: Repositório Público
Como Isso Acontece
O Lovable, por exemplo, cria um repositório no seu GitHub quando você faz deploy. Por padrão, esse repo pode ficar público. Isso significa que qualquer pessoa pode:
- Ver todo o seu código-fonte
- Encontrar chaves de API (Supabase, Stripe, OpenAI...)
- Entender a estrutura completa do seu banco de dados
- Descobrir endpoints não protegidos
- Copiar sua lógica de negócio inteira
💡 Teste agora: Vá em github.com/seu-usuario e veja se seus projetos Lovable/Bolt estão como "Public". Se estiverem, siga os passos abaixo imediatamente.
🟢 Como Corrigir
# Passo 1: Tornar o repositório privado
# Vá em GitHub → seu-repo → Settings → rolar até "Danger Zone"
# Clique em "Change visibility" → "Make private"
# Passo 2: Se já estava público, TODAS as chaves foram expostas
# Mesmo tornando privado agora, o git history (e caches do Google/GitHub)
# ainda tem as chaves antigas. Você PRECISA trocá-las:
# - Supabase: Dashboard → Settings → API → Generate new keys
# - Stripe: Dashboard → Developers → API keys → Roll keys
# - OpenAI: platform.openai.com → API keys → Create new → Delete old
# - Qualquer outro serviço: revogar e gerar nova chave
# Passo 3: Garantir que .env não vai pro git nunca mais
echo ".env" >> .gitignore
echo ".env.local" >> .gitignore
echo ".env.production" >> .gitignore
git rm --cached .env 2>/dev/null # Remove do tracking se já foi commitado
git commit -m "fix: remove env from tracking"
Plataforma por Plataforma: O Que Cada Uma Faz de Errado
1. Lovable — Repo Público + Supabase Keys
O Lovable é incrível para prototipar — você descreve um SaaS e ele gera tudo: frontend React, backend Supabase, autenticação, deploy. Mas ele frequentemente:
- Cria repositório público
- Coloca a
SUPABASE_ANON_KEYdireto no código (não em .env) - Gera tabelas no Supabase sem Row Level Security (RLS)
- Não configura políticas de acesso adequadas
O que é RLS? É a funcionalidade do Supabase (PostgreSQL) que define quem pode ver/modificar cada linha do banco. Sem RLS, qualquer pessoa com a anon key pode ler TODOS os dados de TODAS as tabelas.
-- ❌ Tabela SEM RLS — qualquer um com a anon key lê tudo
CREATE TABLE invoices (
id uuid PRIMARY KEY,
user_id uuid REFERENCES auth.users(id),
amount decimal,
status text
);
-- A anon key do Supabase permite: SELECT * FROM invoices → retorna TUDO
-- ✅ Com RLS — cada usuário só vê seus dados
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can only see own invoices" ON invoices
FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "Users can only insert own invoices" ON invoices
FOR INSERT WITH CHECK (auth.uid() = user_id);
💡 Dica: No dashboard do Supabase, vá em Authentication → Policies. Se você vê tabelas sem nenhuma policy listada, elas estão abertas para qualquer um.
2. Bolt.new — Chaves de API no JavaScript do Browser
O Bolt.new roda tudo no browser via StackBlitz. Quando ele gera código com integrações (Supabase, OpenAI, Stripe), as chaves frequentemente vão direto no JavaScript que é enviado ao browser do usuário.
Por que isso é grave? Qualquer pessoa pode abrir o DevTools (F12) → Sources → e procurar pela chave. Ou simplesmente rodar:
// No console do browser do seu SaaS, um atacante roda:
// Ctrl+Shift+J → Console
fetch('/api/config').then(r => r.json()).then(console.log)
// Ou simplesmente busca no código-fonte:
// Sources → search → "sk_" ou "eyJ" ou "api_key"
🟢 Regra de ouro: Qualquer chave que começa com sk_, sk- ou que é uma service_role nunca pode estar no frontend. Somente chaves marcadas como "públicas" ou "anon" podem estar no código do browser — e mesmo assim, precisam de RLS/policies no backend.
// ✅ Em Next.js, NEXT_PUBLIC_ = vai pro browser, sem prefix = só server
// .env.local
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co // OK no browser
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ... // OK no browser (com RLS!)
SUPABASE_SERVICE_ROLE_KEY=eyJ... // SÓ no server
STRIPE_SECRET_KEY=sk_live_... // SÓ no server
OPENAI_API_KEY=sk-... // SÓ no server
3. v0 da Vercel — Componentes Bonitos, Sem Segurança
O v0 gera componentes React/Next.js com design profissional usando shadcn/ui e Tailwind. Mas ele foca 100% na interface — não adiciona nenhuma camada de segurança.
Problemas comuns:
- Formulários sem validação server-side (só validação no browser, que é facilmente burlada)
- Uso de
dangerouslySetInnerHTMLsem sanitização - Links externos sem
rel="noopener noreferrer" - Sem proteção CSRF em forms que fazem POST
// ❌ Gerado pelo v0 — só valida no frontend
'use client';
export default function ContactForm() {
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const name = (e.target as any).name.value;
if (name.length < 2) return alert('Nome muito curto'); // Só no browser!
fetch('/api/contact', { method: 'POST', body: JSON.stringify({ name }) });
};
return <form onSubmit={handleSubmit}>...</form>
}
// ✅ Validação TAMBÉM no server (API Route)
// app/api/contact/route.ts
import { z } from 'zod';
const schema = z.object({
name: z.string().min(2).max(100).trim(),
email: z.string().email().max(255),
message: z.string().min(10).max(5000).trim(),
});
export async function POST(req: Request) {
const body = await req.json();
const parsed = schema.safeParse(body);
if (!parsed.success) {
return Response.json({ error: parsed.error.flatten() }, { status: 400 });
}
// Processar com dados validados: parsed.data
}
💡 Lembre-se: Validação no frontend é UX (experiência do usuário). Validação no backend é segurança. Você precisa das duas.
4. Claude Code — Express Sem Proteção
O Claude Code é poderoso — ele cria servidores Node.js/Express completos. Mas ele nunca adiciona middleware de segurança por padrão:
// ❌ Servidor típico do Claude Code
const app = express();
app.use(express.json());
// Pronto, começa a criar rotas...
// Sem helmet, cors, rate-limit, validação
// ✅ Starter seguro — copie isso para todo projeto
import express from 'express';
import helmet from 'helmet';
import cors from 'cors';
import rateLimit from 'express-rate-limit';
const app = express();
// Headers de segurança (X-Content-Type-Options, CSP, etc)
app.use(helmet());
// CORS restrito
app.use(cors({
origin: process.env.FRONTEND_URL, // Só seu domínio
credentials: true
}));
// Rate limiting global
app.use(rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutos
max: 100, // 100 requests por IP
standardHeaders: true
}));
// Limitar tamanho do body
app.use(express.json({ limit: '10kb' }));
💡 Dica: Salve esse snippet como "starter seguro". Toda vez que o Claude Code gerar um server Express novo, cole isso no topo antes de qualquer rota.
5. GitHub Copilot — Autocomplete Sem Consciência
O Copilot é um autocomplete — ele prevê a próxima linha com base em padrões. Ele não entende seu contexto de segurança. Fique atento quando ele sugerir:
eval(userInput)— nunca aceitecors({ origin: '*' })— troque pelo seu domíniosql\`SELECT * FROM users WHERE id = ${id}\`— use parametrização- Qualquer hardcoded secret — mova para .env
6. Google Apps Script — Permissões Excessivas
Quando a IA gera scripts para Google Workspace, ela pede todas as permissões possíveis. O manifesto appsscript.json acaba com escopos como auth/drive (acesso total ao Drive) quando só precisaria de auth/drive.file (só arquivos do app).
// ❌ Escopos demais
{
"oauthScopes": [
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/gmail.modify",
"https://www.googleapis.com/auth/spreadsheets"
]
}
// ✅ Escopos mínimos
{
"oauthScopes": [
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/spreadsheets.currentonly"
]
}
💡 Dica: Abra appsscript.json no seu projeto e revise cada escopo. Pergunte-se: "Este script REALMENTE precisa de acesso total?"
Ferramentas Para Detectar Problemas Automaticamente
Existem ferramentas gratuitas que escaneiam seu repositório procurando secrets e vulnerabilidades:
# GitLeaks — detecta secrets no histórico git
# Instalar: brew install gitleaks (Mac) ou baixar de github.com/gitleaks/gitleaks
gitleaks detect --source . --report-format json
# npm audit — verifica dependências JavaScript
npm audit
npm audit fix
# Snyk — scan mais completo (gratuito para projetos open source)
npx snyk test
# TruffleHog — busca secrets no git history inteiro
trufflehog git file://. --only-verified
Checklist Final: 15 Itens Para Todo Projeto de Vibe Coding em JS
- ☐ Repositório privado no GitHub
- ☐
.envno .gitignore (antes do primeiro commit!) - ☐ Chaves de API em variáveis de ambiente, nunca hardcoded
- ☐
service_roleesk_keys só no server-side - ☐ Supabase com RLS ativado em todas as tabelas
- ☐ helmet() no Express/Fastify
- ☐ CORS restrito ao domínio de produção
- ☐ Rate limiting em endpoints públicos
- ☐ Inputs validados com Zod no server
- ☐
dangerouslySetInnerHTMLcom DOMPurify - ☐ JWT com expiração + httpOnly cookie
- ☐ npm audit sem vulnerabilidades críticas
- ☐ Git history escaneado com GitLeaks
- ☐ Google Apps escopos OAuth mínimos
- ☐ Dependabot ativado no repositório
Conclusão
Lovable, Bolt.new, v0, Claude Code e Copilot são ferramentas incríveis. Elas colocam o poder de construir software na mão de qualquer pessoa. Mas facilidade de deploy não é sinônimo de segurança.
O passo mais importante que você pode dar agora — literalmente agora — é abrir o GitHub e verificar se seus repositórios estão privados. Se não estiverem, torne-os privados e troque todas as chaves. Esses 10 minutos podem salvar seu projeto.
Lembre-se: A IA constrói rápido. Mas segurança continua sendo responsabilidade humana.