📊 Os dados: 45% do código de IA tem falhas de segurança
Antes de qualquer técnica, é essencial entender a escala do problema com dados concretos. O código gerado por IA não é inerentemente inseguro — mas ele reproduz os padrões de segurança (e insegurança) que existem nos dados de treinamento.
📊 Dados verificados de pesquisa (2024–2025)
📉 Distribuição dos tipos de vulnerabilidade em código de IA
⚠️ Por que a IA comete erros de segurança
A IA aprende de exemplos online onde credenciais aparecem hardcodadas para simplificação, onde input não é validado em tutoriais rápidos, onde ownership não é verificado em código de demonstração. O modelo não distingue código de produção de código educacional.
Além disso, a IA otimiza para "funcionar" — não para "funcionar com segurança". Segurança requer instrução explícita e consistente em cada contexto de prompt e nos arquivos de regras.
🔟 OWASP Top 10 para código de IA
O OWASP Top 10 lista as vulnerabilidades mais críticas de aplicações web. A IA cria todas elas, mas as 5 mais frequentes têm padrões identificáveis que você pode detectar e prevenir com instruções específicas.
SQL Injection
Como a IA cria: concatena variáveis diretamente em queries SQL, especialmente em exemplos "quick start". Muito comum quando a IA assume que você está prototipando.
Vulnerável — IA gera sem instrução
// PERIGOSO: SQL Injection
const query = `
SELECT * FROM users
WHERE email = '${email}'
AND password = '${password}'
`;
// Atacante envia: ' OR '1'='1
// Resultado: acessa qualquer conta
Seguro — com instrução no CLAUDE.md
// SEGURO: ORM parametrizado
const user = await prisma.user.findFirst({
where: {
email,
password: hashedPassword
}
});
// Prisma sanitiza automaticamente
// Nunca interpolação de string
Instrução no CLAUDE.md:
NUNCA usar SQL raw com interpolação de string. SEMPRE usar Prisma ou queries parametrizadas ($1, $2). Sem exceções.
XSS — Cross-Site Scripting
Como a IA cria: usa innerHTML para renderizar conteúdo dinâmico — é mais simples de escrever e muito comum em tutoriais de JavaScript. Permite injeção de scripts maliciosos.
Vulnerável
// PERIGOSO: XSS
element.innerHTML = userInput;
// Atacante: <script>steal(cookie)</script>
// Também perigoso:
document.write(data.comment);
container.innerHTML = `<p>${name}</p>`;
Seguro
// SEGURO: textContent escapa automaticamente
element.textContent = userInput;
// Ou sanitize com DOMPurify quando HTML é necessário:
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);
Instrução no CLAUDE.md:
NUNCA usar innerHTML com dados de usuário. SEMPRE textContent para texto. Se HTML é necessário, usar DOMPurify.sanitize() obrigatoriamente.
IDOR — Insecure Direct Object Reference
Como a IA cria: busca recursos pelo ID do parâmetro sem verificar se o usuário autenticado é o dono. É a vulnerabilidade #1 em código de IA — extremamente fácil de introduzir, fácil de explorar.
Vulnerável — MUITO comum em código de IA
// PERIGOSO: qualquer usuário acessa
app.get('/orders/:id', async (req, res) => {
const order = await prisma.order.findUnique({
where: { id: req.params.id }
// Sem verificar userId!
});
res.json(order);
});
// GET /orders/123 revela pedido de outro usuário
Seguro — ownership verificado
// SEGURO: verifica ownership obrigatoriamente
app.get('/orders/:id', auth, async (req, res) => {
const order = await prisma.order.findFirst({
where: {
id: req.params.id,
userId: req.user.id // CRÍTICO!
}
});
if (!order) return res.status(404).json({});
res.json(order);
});
Instrução no CLAUDE.md:
SEMPRE verificar req.user.id ao acessar qualquer recurso. NUNCA confiar em parâmetros de URL sem validar ownership. Em CADA query de recurso privado: where: { id, userId: req.user.id }
Broken Authentication
Como a IA cria: middleware de auth esquecido em algumas rotas, tokens sem expiração, refresh tokens implementados incorretamente, senhas sem hash adequado.
Vulnerável
// PERIGOSO: rota admin sem proteção
app.get('/admin/users', async (req, res) => {
const users = await prisma.user.findMany();
res.json(users);
});
// PERIGOSO: senha sem hash
await prisma.user.create({
data: { email, password } // plaintext!
});
Seguro
// SEGURO: auth + role check
app.get('/admin/users', auth, requireRole('admin'),
async (req, res) => {
const users = await prisma.user.findMany();
res.json(users);
}
);
// SEGURO: bcrypt hash
const hashed = await bcrypt.hash(password, 12);
await prisma.user.create({ data: { email,
password: hashed } });
Cryptographic Failures / Exposed Secrets
Como a IA cria: hardcoda API keys, connection strings e JWT secrets diretamente no código. Aprende de tutoriais onde isso é feito por simplicidade didática.
Vulnerável — IA gera assim
const jwt = require('jsonwebtoken');
// PERIGOSO: secret hardcodado
const token = jwt.sign(payload, 'minha_chave_123');
const stripe = new Stripe('sk_live_abc...xyz');
const db = new Client({
connectionString: 'postgres://user:pass@host/db'
});
Seguro
const jwt = require('jsonwebtoken');
// SEGURO: sempre process.env
const token = jwt.sign(payload, process.env.JWT_SECRET!);
const stripe = new Stripe(process.env.STRIPE_KEY!);
const db = new Client({
connectionString: process.env.DATABASE_URL
});
📋 Bloco de segurança obrigatório no CLAUDE.md
## Regras de Segurança (OBRIGATÓRIAS — sem exceções)
- SEMPRE verificar req.user.id ao acessar dados do usuário
- NUNCA confiar em parâmetros de URL sem validar ownership
- SEMPRE usar ORM parametrizado (Prisma) — nunca SQL raw com input
- NUNCA retornar stack traces ou mensagens de erro internas em produção
- SEMPRE validar e sanitizar input com Zod antes de processar
- NUNCA usar innerHTML com dados de usuário — usar textContent ou DOMPurify
- NUNCA hardcodar secrets — sempre process.env
- SEMPRE hashear senhas com bcrypt (rounds >= 12)
- SEMPRE adicionar middleware de auth em TODAS as rotas privadas
- SEMPRE criar políticas RLS ao criar novas tabelas no Supabase
🛡️ Row Level Security — o erro mais comum em apps Supabase
Row Level Security (RLS) é uma funcionalidade do PostgreSQL/Supabase que garante que usuários só acessam seus próprios dados no nível do banco de dados, independente do que a aplicação faça. É a última linha de defesa e a mais frequentemente esquecida em vibe coding.
Tabela vulnerável — sem RLS
-- Tabela criada pela IA sem instrução
CREATE TABLE orders (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
user_id uuid REFERENCES auth.users(id),
total decimal(10,2),
status text,
created_at timestamptz DEFAULT now()
);
-- RLS não habilitado!
-- Resultado: qualquer usuário autenticado
-- pode fazer: SELECT * FROM orders
-- e ver TODOS os pedidos de TODOS os usuários
-- via API Supabase exposta no frontend
Tabela segura — com RLS obrigatório
CREATE TABLE orders (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
user_id uuid REFERENCES auth.users(id) NOT NULL,
total decimal(10,2),
status text,
created_at timestamptz DEFAULT now()
);
-- OBRIGATÓRIO após criar qualquer tabela:
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
-- Usuário vê apenas seus próprios pedidos
CREATE POLICY "users_own_orders" ON orders
FOR ALL USING (auth.uid() = user_id);
-- Admin vê tudo (opcional)
CREATE POLICY "admins_all_orders" ON orders
FOR ALL USING (
EXISTS (SELECT 1 FROM profiles
WHERE id = auth.uid() AND role = 'admin')
);
💬 Prompt para solicitar RLS à IA
"Adicione Row Level Security completo para estas tabelas
Supabase. Para cada tabela:
1. ALTER TABLE ... ENABLE ROW LEVEL SECURITY
2. Policy para usuários autenticados verem apenas
seus próprios dados (where user_id = auth.uid())
3. Policy para admins verem todos os dados
(verificar role na tabela profiles)
4. Se a tabela for pública (ex: produtos de um catálogo),
criar policy de leitura pública explícita
Tabelas: orders, profiles, documents, notifications
IMPORTANTE: Sem RLS habilitado, a API Supabase expõe
todos os dados de todos os usuários para qualquer
usuário autenticado."
🚨 O Incidente Lovable — 18.000 usuários expostos (2025)
Um app construído com Lovable (plataforma de vibe coding) foi exposto: sem RLS configurado, qualquer usuário autenticado conseguia acessar dados de qualquer outro usuário fazendo requests diretos à API do Supabase — que o Lovable expõe automaticamente via anon key no frontend.
18.000 usuários tiveram dados potencialmente expostos. O problema: Lovable não ativava RLS por padrão, e a IA não adicionava políticas de RLS sem instrução explícita.
Uma linha de instrução no CLAUDE.md previne este incidente: "SEMPRE habilitar RLS e criar policies ao criar novas tabelas Supabase."
🔑 Gestão de secrets — never hardcode, never commit
Secrets hardcodados é um dos erros mais comuns e mais devastadores em código de IA. O modelo aprende de exemplos online onde credenciais frequentemente aparecem hardcodadas para simplificação. Você precisa instruir explicitamente contra isso.
✗ NÃO FAÇA — IA gera assim sem instrução
// NUNCA hardcodar
const stripe = new Stripe(
'sk_live_51NxAbc123...' // exposto no git!
);
const db = new Pool({
password: 'minhasenha123',
host: 'prod-db.amazonaws.com'
});
const token = jwt.sign(
payload, 'chave_secreta_123'
);
// .env nunca deve ser commitado
// mas a IA pode colocar valores reais
✓ SEMPRE assim — variáveis de ambiente
// SEMPRE process.env
const stripe = new Stripe(
process.env.STRIPE_SECRET_KEY!
);
const db = new Pool({
connectionString: process.env.DATABASE_URL
});
const token = jwt.sign(
payload,
process.env.JWT_SECRET!,
{ expiresIn: '1h' }
);
🔍 Onde secrets podem vazar — checklist completo
- Código-fonte commitado no git
- Logs de aplicação (evitar logar req.body completo)
- Variáveis de ambiente no frontend (expostas no bundle)
- Respostas de API que retornam objetos inteiros
- Imagens Docker com secrets em layers
- CI/CD logs com variáveis impressas
- Stack traces expostos em produção
- Arquivos .env no repositório (sem .gitignore)
🔍 Prompt para auditar código existente
"Audite este codebase em busca de secrets hardcodados
e práticas inseguras de gestão de credenciais.
Procure por:
1. Strings que parecem API keys, tokens ou senhas
(padrões: sk_live_, Bearer , postgres://, etc.)
2. Variáveis com nomes como: secret, password, key,
token, credential, api_key
3. Variáveis de ambiente usadas diretamente
(sem process.env)
4. Conexões de banco com credenciais inline
5. JWT secrets hardcodados
Para cada ocorrência encontrada:
- Linha do código
- Tipo de secret
- Risco (alto/médio/baixo)
- Como corrigir
Arquivos a auditar: @src/"
🔐 Checklist de Gestão de Secrets
- ✓.env no .gitignore — sempre, sem exceção
- ✓.env.example com chaves vazias — no repositório para documentar variáveis necessárias
- ✓git-secrets ou trufflehog — scan automático de commits para detectar secrets acidentais
- ✓GitHub Secret Scanning — alertas automáticos se um secret detectado é pushado
- ✓Rotate imediatamente — se um secret foi commitado, rotacione antes de corrigir o commit
🔍 SAST: análise estática automatizada
SAST (Static Application Security Testing) analisa o código sem executá-lo, detectando vulnerabilidades antes do deploy. Em um fluxo de vibe coding, SAST deve rodar automaticamente em cada commit ou PR — não manualmente depois.
📊 Comparativo de ferramentas SAST
| Ferramenta | Tier gratuito | O que detecta | Integração |
|---|---|---|---|
| Snyk | 200 testes/mês (open source: ilimitado) | Dependências vulneráveis, código, containers | IDE, GitHub Actions, CI/CD |
| SonarQube | Community Edition gratuita (self-hosted) | Qualidade de código + vuln. de segurança, 30+ linguagens | PR gates, CI/CD, VSCode plugin |
| Semgrep | Gratuito para open source, rules públicas | Patterns OWASP, secrets, regras customizáveis | GitHub Actions, pre-commit, CLI |
| GitHub Code Scanning | Gratuito para repos públicos e private (CodeQL) | Vulnerabilidades complexas com análise de fluxo de dados | Nativo no GitHub, PR annotations |
⚙️ GitHub Action: SAST completo em cada PR
# .github/workflows/security.yml
name: Security Scan
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
sast:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Semgrep: detecta OWASP Top 10 e secrets
- name: Run Semgrep
uses: semgrep/semgrep-action@v1
with:
config: >-
p/security-audit
p/secrets
p/owasp-top-ten
p/typescript
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
# Snyk: verifica dependências com vulnerabilidades
- name: Snyk vulnerability check
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
# npm audit: check rápido de dependências
- name: npm audit
run: npm audit --audit-level=high
👁️ Code review focado em segurança
Mesmo com SAST automatizado, code review humano focado em segurança é insubstituível. O humano detecta falhas de lógica de negócio que ferramentas automatizadas não conseguem — como autorização incorreta que tecnicamente compila mas semanticamente está errada.
📋 Checklist de segurança — 10 itens por categoria
🔐Autenticação e Autorização
- Todas as rotas privadas têm middleware de auth?
- Verificação de ownership em todos os recursos?
- Tokens JWT têm expiração definida?
🔑Secrets e Dados Sensíveis
- Nenhum secret hardcodado no código?
- Dados sensíveis não estão sendo logados?
- RLS configurado em todas as tabelas Supabase?
📥Input e Output
- Todo input de usuário validado com schema (Zod)?
- Queries usam ORM ou parâmetros ($1, $2)?
- Erros não expõem stack trace em produção?
📦Dependências
- Novas dependências auditadas com npm audit?
- Pacotes de origem conhecida e confiável?
💬 Prompt para code review de segurança com IA
"Faça um code review focado exclusivamente em segurança
destes arquivos. Não avalie qualidade de código ou estilo.
Procure especificamente por:
1. IDOR: endpoints que não verificam ownership
2. SQL Injection: queries com interpolação de string
3. XSS: uso de innerHTML com dados de usuário
4. Secrets expostos: hardcoded ou logados
5. Auth missing: rotas que deveriam ter auth mas não têm
6. RLS missing: tabelas Supabase sem policies
7. Sensitive data in logs: dados sensíveis em console.log
8. Error disclosure: stack traces retornados ao cliente
Para cada problema encontrado:
- Arquivo e linha
- Tipo de vulnerabilidade (OWASP A0X)
- Severidade: Crítica / Alta / Média
- Código vulnerável vs. código corrigido
Arquivos: @src/routes/ @src/controllers/"
💀 Casos reais de incidentes — o que aconteceu e por quê
Estudar casos reais é a forma mais eficaz de internalizar a importância de segurança. Estes não são cenários hipotéticos — são incidentes documentados que afetaram usuários reais de plataformas e apps de vibe coding em 2025.
Lovable — 18.000 usuários com dados expostos
Março 2025 · Plataforma de vibe coding no-codeO que aconteceu
Pesquisador de segurança descobriu que apps gerados pelo Lovable não tinham RLS habilitado no Supabase por padrão. Qualquer usuário autenticado podia acessar dados de qualquer outro via API pública.
Causa raiz
A plataforma não habilitava RLS por padrão. A IA não adicionava políticas de RLS sem instrução explícita. A anon key do Supabase no frontend dava acesso a todas as linhas de todas as tabelas.
Como prevenir
Instrução no CLAUDE.md: "SEMPRE habilitar RLS e criar policy ao criar tabela." Verificação: nunca deploy sem confirmar RLS em 100% das tabelas com dados de usuário.
Base44 — vazamento de dados de clientes empresariais
Abril 2025 · Plataforma SaaS gerada com IAO que aconteceu
Funcionalidade de exportação de relatórios gerada por IA não validava que o usuário tinha acesso aos dados solicitados. Usuário de empresa A conseguia exportar dados da empresa B passando um ID diferente na URL.
Causa raiz
IDOR clássico (A01 OWASP). A IA gerou o endpoint sem verificar ownership do tenant. O endpoint recebia tenant_id como parâmetro e retornava os dados sem checar se pertenciam ao usuário autenticado.
Como prevenir
NUNCA confiar em IDs de URL sem verificar no banco que pertencem ao usuário autenticado. Em multi-tenant: sempre filtrar por tenant_id extraído do token JWT, nunca do body/params.
CurXecute — CVE-2025-54135 · Privilege escalation por prompt injection
Junho 2025 · Plugin de IDE para agentes de IAO que aconteceu
Plugin de IDE para agentes de vibe coding executava código arbitrário via prompt injection. Um arquivo malicioso no repositório continha instruções disfarçadas que o agente interpretava como comandos legítimos, executando com as permissões do desenvolvedor.
Causa raiz
Agent privilege escalation: o plugin não sanitizava o conteúdo de arquivos antes de passá-los ao contexto do agente. Conteúdo de arquivos de terceiros (dependências, arquivos clonados) podia injetar instruções no agente.
Como prevenir
Cuidado com plugins de IDE de origem desconhecida. Agentes com acesso ao filesystem são vetores de ataque. Revise permissões de cada plugin. Nunca execute agentes com permissões de root ou admin desnecessárias.
💡 O padrão comum entre os incidentes
Os três incidentes têm um denominador comum: a IA gerou código funcional, mas sem as verificações de segurança que um desenvolvedor experiente aplicaria instintivamente. A IA não tem "instinto de segurança" — ela precisa de instrução explícita.
Todos eram preveníveis com: (1) instruções de segurança no CLAUDE.md, (2) SAST automatizado no CI, (3) code review de segurança antes de cada deploy. Nenhum exigia conhecimento de segurança avançado.
✅ Resumo do Módulo 4.4
Próximo Módulo:
4.5 — 🧪 Testes Automatizados com IA: o guardrail que permite vibe coding seguro em produção