Sua IA escreveu o código. Subiu rápido. Funcionou. Agora vem a parte que ninguém te ensina: descobrir o que ficou aberto.
Tem uma frase circulando entre desenvolvedores que resume o momento atual: "Eu não escrevo mais código, eu converso com a IA até a aplicação existir". É o tal do vibe coding — termo popularizado por Andrej Karpathy em 2025 — onde você descreve a ideia, a IA gera o código, você ajusta, ela ajusta, e em poucas horas tem um produto rodando.
E funciona. Eu mesmo já tirei MVP do papel num fim de semana usando Cursor + Claude. O problema não é a velocidade. O problema é o resíduo invisível que esse processo deixa.
O .env que ficou no repo público. A chave de API hardcoded num arquivo de teste que ninguém apagou. O endpoint admin sem autenticação. A pasta /uploads listável. O wp-config.php.bak que o editor criou e o deploy levou junto.
Esses problemas não são novos. O que é novo é a escala. Quando você delega geração de código pra uma IA e move rápido, certos hábitos de segurança simplesmente nunca entram no fluxo. Como o resultado funciona, ninguém volta pra checar.
💭 Esse artigo é sobre auditar sua própria aplicação com as mesmas ferramentas que um atacante usaria. Não é sobre invadir o site dos outros. É sobre olhar o seu antes que alguém olhe.
⚖️ Antes de qualquer coisa: o aviso que ninguém pode pular
🚨 AVISO LEGAL
Tudo que vou mostrar aqui é pra ser usado em uma de duas situações:
- Sua própria aplicação — código seu, infra sua, conta sua.
- Aplicação de terceiro com autorização explícita por escrito — contrato de pentest, programa de bug bounty público (HackerOne, Bugcrowd, Intigriti).
Rodar essas ferramentas contra sites aleatórios é crime no Brasil — invasão de dispositivo informático (art. 154-A do CP), pena de até 2 anos. Use no seu ambiente.
Dito isso, vamos ao que interessa.
🐉 O ambiente: Kali Linux num container
Você não precisa instalar Kali na sua máquina principal. Eu rodo num container Docker, isolado, que sobe quando preciso e fica desligado o resto do tempo.
# Sobe o container
docker run -it --rm \
-v $(pwd)/data:/root/data \
kalilinux/kali-rolling /bin/bash
# Dentro dele:
apt update
apt install -y wpscan nikto nmap whatweb gobuster metasploit-framework
msfdb init
Pronto. Laboratório portátil. Se quiser interface gráfica acessível pelo navegador (útil pra Burp Suite), dá pra adicionar XFCE + noVNC, mas pra varredura de linha de comando o terminal basta.
🔍 Reconhecimento: o que sua aplicação está dizendo pro mundo
Antes de "scanear vulnerabilidades", o passo zero é descobrir o que está exposto. E aqui mora a primeira surpresa de quem fez vibe coding: muito mais coisa do que você imagina.
whatweb — quem você é, na real?
Em segundos, ele te diz o que está rodando no servidor. Cada informação é uma chave que um atacante usa pra correlacionar com CVEs.
$ whatweb https://meusite.com
Output típico:
https://meusite.com [200 OK]
Apache[2.4.41]
Cookies[wordpress_test_cookie]
HTTPServer[Apache/2.4.41 (Ubuntu)]
JQuery[3.6.0]
MetaGenerator[WordPress 6.4.2] ← versão exposta
PHP[8.1.2] ← versão exposta
WordPress[6.4.2] ← versão exposta
X-Powered-By[PHP/8.1.2] ← versão exposta
⚠️ 4 informações sensíveis vazando em headers
Se sua app vibe-coded está vazando "Powered by Express 4.16.0" no header, você sabe que precisa esconder isso (app.disable('x-powered-by')). É uma linha que ninguém te lembrou de colocar.
gobuster — as portas que você esqueceu de fechar
Esse aqui é o que mais expõe descuido em projeto vibe-coded. Ele faz bruteforce de diretórios e arquivos baseado em wordlists.
gobuster dir -u https://meusite.com \
-w /usr/share/wordlists/dirb/common.txt \
-x php,html,txt,bak,old,zip,env,git
Output real do que ele encontra em apps inseguras:
═══════════════════════════════════════════════════
Gobuster v3.6 — varredura iniciada
═══════════════════════════════════════════════════
/.env (Status: 200) [Size: 412] 🔥 CATÁSTROFE
/.git/config (Status: 200) [Size: 92] 🔥 REPO INTEIRO ACESSÍVEL
/admin (Status: 200) [Size: 2841] ⚠️ sem auth?
/backup.zip (Status: 200) [Size: 8412334] ⚠️
/config.php.bak (Status: 200) [Size: 1284] ⚠️
/phpinfo.php (Status: 200) [Size: 71028] ⚠️
/uploads/ (Status: 301) [Size: 178] ⚠️ listável
/test (Status: 200) [Size: 412] ⚠️
/wp-config.php.old (Status: 200) [Size: 3211] ⚠️
Progress: 4614 / 4614 (100.00%)
⚠️ 9 endpoints suspeitos encontrados
😱 "Mas como o
.envficou acessível?"O dev nunca pensou que
https://app.com/.envera acessível porque "tá na pasta do servidor, ué". Tá. E o servidor serve a pasta inteira. É exatamente assim que vaza.
O que o atacante encontra dentro do .env
Quando ele baixa esse arquivo, vê algo parecido com isso:
# 📄 .env recém-baixado de https://meusite.com/.env
# ────────────────────────────────────────────────
# Database
DB_HOST=db.meusite.com
DB_USER=admin
DB_PASSWORD=P@ssw0rd_Production_2024!
DB_NAME=main_production
# API Keys
OPENAI_API_KEY=sk-proj-aB3kK9...M2pQrXyZ
STRIPE_SECRET_KEY=sk_live_51M8d2K...yT9nQ4w
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7M...EXAMPLEKEY
# Auth
JWT_SECRET=muito_secreto_123_nao_compartilhar
SESSION_SECRET=qwerty12345
# SMTP
SMTP_PASSWORD=EmailM4ster99
Em 30 segundos um desconhecido tem:
- 🗄️ Acesso total ao seu banco
- 💳 Sua chave Stripe pra fazer transações
- 🤖 Sua chave OpenAI pra queimar créditos
- ☁️ Suas credenciais AWS pra subir instâncias na sua conta
Tudo de graça. Tudo porque um arquivo de 412 bytes ficou acessível.
A correção é simples (e ninguém faz)
No nginx, bloqueia explicitamente arquivos sensíveis:
# /etc/nginx/sites-available/meusite.conf
location ~ /\. { deny all; }
location ~ \.(env|bak|old|zip|sql|log)$ { deny all; }
location ~ /\.git { deny all; }
# Proteção extra para WordPress:
location ~* /(?:uploads|files)/.*\.php$ { deny all; }
✅ Boa prática: nunca subir
.envpro servidor de produção. Variáveis de ambiente vão direto no painel da hospedagem, no Docker, no systemd — em qualquer lugar que não seja arquivo dentro do webroot.
🔌 WPScan — pra quando seu vibe coding virou WordPress
Boa parte das aplicações que vejo serem montadas rapidinho começa como WordPress + alguns plugins + um tema gratuito. E aí entra o WPScan, ferramenta dedicada ao ecossistema WP.
Pega uma API key gratuita em wpscan.com (necessária pra checar vulnerabilidades) e roda:
wpscan --url https://meusite.com \
--enumerate vp,vt,u \
--api-token SEU_TOKEN
Onde:
| Flag | O que enumera |
|---|---|
vp |
Plugins vulneráveis |
vt |
Temas vulneráveis |
u |
Usuários do WP |
Output real:
[i] Target URL: https://meusite.com/
[+] WordPress version 6.2.1 (INSEGURA, lançada 2023-05-16)
| Vulnerável a 8 vulnerabilidades conhecidas
[+] WordPress theme: astra v4.1.0
[!] PLUGIN VULNERÁVEL: contact-form-7
| Versão: 5.7.1
| Última: 5.9.2
| CVE-2023-6449 — Stored XSS via file upload
| Severidade: HIGH (8.1)
| Fix: atualizar para 5.7.4+
[!] PLUGIN VULNERÁVEL: elementor
| Versão: 3.5.2
| CVE-2023-48777 — Authenticated File Upload
| Severidade: CRITICAL (9.8)
[!] USUÁRIOS IDENTIFICADOS:
| admin (mensagem de erro de login + author archive)
| joao (author archive)
| marketing (author archive)
────────────────────────────────────────
⚠️ 2 plugins vulneráveis · 3 usuários enumerados
💡 O que fazer com esse output?
Cada CVE listada tem severidade e correção. "Plugin X versão Y → atualize pra Z". É ouro: em três comandos você sabe exatamente o que está furado.
A enumeração de usuários (
-u) é especialmente perigosa — se o WP retorna usuários válidos, o atacante já tem metade do bruteforce pronto.
🛠️ Nikto — o velho de guerra que ainda funciona
Nikto é de 2001 e segue extremamente útil. Varre o servidor procurando configurações inseguras, arquivos perigosos, headers ausentes, versões desatualizadas.
nikto -h https://meusite.com -o relatorio.html -Format html
Tipo de coisa que ele acha em apps vibe-coded:
+ Server: Apache/2.4.41 (Ubuntu)
+ ❌ X-Frame-Options header NÃO está setado.
└─ Permite clickjacking
+ ❌ X-Content-Type-Options header NÃO está setado.
└─ Permite MIME sniffing attacks
+ ❌ Strict-Transport-Security header NÃO setado.
└─ Permite downgrade pra HTTP
+ ⚠️ Cookie PHPSESSID criado sem flag httponly.
+ ⚠️ Métodos HTTP permitidos: GET, HEAD, POST, OPTIONS, PUT, DELETE
└─ PUT e DELETE expostos sem auth
+ ❌ /readme.html: arquivo default do Apache
+ ❌ /phpinfo.php: PHP information disclosure
+ ⚠️ /uploads/: directory indexing habilitado
+ ❌ /admin/: página admin acessível
────────────────────────────────────────
⚠️ 6 issues HIGH · 3 issues MEDIUM
Cada uma dessas linhas é uma classe de ataque que você está deixando aberta. X-Frame-Options ausente vira clickjacking. HSTS ausente vira downgrade pra HTTP. PUT/DELETE abertos viram qualquer coisa.
⚠️ Cuidado com Nikto em produção.
Ele é barulhento — faz milhares de requests rapidamente. Não rode contra produção sem avisar antes, ou use rate limiting. Em staging é tranquilo.
🔐 Procurando segredos vazados: o pesadelo das chaves de API
Aqui chegamos ao tema mais doloroso da era vibe coding. Modelos de IA são treinados em código público — e às vezes deixam exemplos com chaves placeholder que parecem placeholders mas o dev esqueceu de trocar. Ou pior: a IA sugere colocar a chave direto no frontend.
trufflehog — caça-segredos no seu próprio repo
Antes mesmo de subir nada, rode no seu repositório:
docker run --rm -v "$PWD:/repo" \
trufflesecurity/trufflehog:latest \
filesystem /repo --only-verified
Output quando algo é encontrado:
🐷🔑🐷 TruffleHog. Unearth your secrets.
══════ Found verified result ══════
Detector Type: OpenAI
File: ./src/lib/ai.js
Line: 14
Verified: ✅ true
Raw: sk-proj-aB3kK9...M2pQrXyZ
══════ Found verified result ══════
Detector Type: AWS
File: ./scripts/deploy.sh
Line: 7
Verified: ✅ true
Raw: AKIAIOSFODNN7EXAMPLE
══════ Found verified result ══════
Detector Type: Stripe
File: ./.env.example
Line: 12
Verified: ✅ true
Raw: sk_live_51M8d2K...yT9nQ4w
────────────────────────────────────────
⚠️ 3 segredos VERIFICADOS no repositório
⚠️ Todos ainda funcionando contra a API real
A flag --only-verified é importante: ela pega apenas segredos que o TruffleHog conseguiu validar com a API correspondente. Sem isso, vem muito falso positivo. Com ela, se aparece resultado, é real e é urgente.
🚨 Achou um segredo vazado? Protocolo de emergência
1️⃣ Revogue a chave imediatamente
No painel do serviço. Não "rotacione depois", revogue agora. Se já foi pro repo público, considere comprometida desde o segundo zero.
2️⃣ Gere uma nova e atualize as variáveis de ambiente
Direto no painel da hospedagem (Vercel, Hostinger, AWS, Heroku). Nunca em arquivo dentro do projeto.
3️⃣ Audite o histórico do Git
git log --all -p | grep -i "trecho_da_chave"
Se já foi commitada em algum momento, ela está pra sempre acessível em forks e clones.
4️⃣ Limpe o histórico (BFG ou git-filter-repo)
Reescrever histórico é dor de cabeça com colaboradores, mas necessário. Avise o time antes.
5️⃣ Revise logs de uso do serviço
Stripe, OpenAI, AWS — todos têm logs de uso por chave. Veja se houve uso suspeito antes da revogação.
gitleaks — proteção em pre-commit
Pra que isso não aconteça de novo, instala o gitleaks como hook de pre-commit:
# Na raiz do repo:
echo '#!/bin/sh
gitleaks protect --staged --verbose' > .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
Quando você tentar commitar uma chave:
$ git add .env
$ git commit -m "add api keys"
○ gitleaks pre-commit hook
╭───────────── leak detected ─────────────╮
│ Finding: OPENAI_API_KEY=sk-proj-... │
│ Secret: sk-proj-aB3kK9...M2pQrXyZ │
│ RuleID: openai-api-key │
│ File: .env │
│ Line: 4 │
╰─────────────────────────────────────────╯
✗ commit aborted: 1 leak found
Bundlers vazando segredos no frontend
Se sua app já está em produção, vale procurar segredos no JavaScript bundleado. Bundlers às vezes empacotam variáveis de servidor por engano:
$ curl -s https://meusite.com/static/js/main.js \
| grep -E "sk_live|AKIA|AIza|ghp_"
apiKey:"AIzaSyB-X9pT...1qWeRtY" ← Google API exposta
stripeKey:"sk_live_51M8d...4w" ← chave LIVE da Stripe!
📌 Variáveis com prefixo público viram públicas.
NEXT_PUBLIC_*,VITE_*,REACT_APP_*são empacotadas no JavaScript que vai pro navegador. Não bote segredo lá. Use serverless functions ou rotas de API pra mediar requisições que precisam de credenciais.
💣 Metasploit — o canivete suíço do pentester
Depois de mapear o que está exposto, Metasploit é a ferramenta pra explorar de fato vulnerabilidades conhecidas. Ele tem módulos pré-prontos pra milhares de CVEs.
$ msfconsole
Fluxo típico — validar se uma correção funcionou:
=[ metasploit v6.4.x ]
+ -- --=[ 2400+ exploits - 1200+ auxiliary ]
msf6 > search type:exploit cve:2024 wordpress
# Name Disclosure Rank
- ---- ---------- -----
0 exploit/unix/webapp/wp_plugin_xyz_rce 2024-03-15 excellent
1 exploit/multi/http/wp_admin_shell_up 2024-01-08 great
msf6 > use 0
msf6 exploit(wp_plugin_xyz_rce) > set RHOSTS meusite.com
msf6 exploit(wp_plugin_xyz_rce) > check
[+] meusite.com:443 - O alvo PARECE VULNERÁVEL
└─ confirme se a atualização foi aplicada
🎯 Use
checkantes derun.O comando
checksó verifica se o alvo é vulnerável, sem explorar de fato. É exatamente o que você quer pra validar correção sem risco de quebrar a aplicação.
Aqui é importante reforçar: o uso responsável do Metasploit é validar que uma correção funcionou. Você descobriu via WPScan que o plugin X tem CVE-2024-XXXX. Atualizou. Como saber se a correção funcionou? Tenta explorar com o módulo Metasploit correspondente. Se falhar, ótimo. Se ainda funcionar, a atualização não foi suficiente.
📋 Workflow semanal pra apps vibe-coded
Junta tudo num roteiro repetível. Eu rodo isso no meu próprio projeto a cada release relevante:
🛡️ Local · pre-commit
gitleaksno hooktrufflehog filesystem . --only-verified- Lint específico da stack:
bandit(Python),npm audit(Node),semgrep,snyk
🔍 Staging · pós-deploy
whatwebpra ver fingerprintgobustercom wordlist de arquivos sensíveisniktopra config do servidorwpscanse for WordPress- Curl manual em endpoints "que você não lembra de ter exposto" (
/api/admin,/.git/config,/.env,/wp-config.php.bak)
🔄 Mensal · rotina
- Rotacionar API keys mesmo sem indício de vazamento
- Atualizar dependências (
apt,npm,composer,pip) - Revisar logs de acesso buscando padrões de scan vindos de terceiros (você não é o único rodando essas ferramentas)
👁️ Cultural · contínuo
- Sempre que pedir pra IA gerar código que lida com auth, secrets, upload, ou input do usuário — leia linha-por-linha antes de aceitar
- IA não escreve código inseguro de propósito, mas escreve código que funciona
- E "funciona" é diferente de "seguro"
🧠 A mentalidade que importa mais que as ferramentas
Vibe coding não é o problema. Ferramentas de IA pra desenvolvimento vieram pra ficar e fazem coisas que eram impossíveis dois anos atrás. O problema é velocidade sem fricção de segurança.
Cada uma das ferramentas que mostrei aqui te dá um momento de fricção saudável. Você roda, ela aponta dez coisas erradas, você corrige cinco e aceita o risco em cinco com consciência. Isso é diferente de subir e torcer.
💎 A diferença entre uma aplicação amadora e uma profissional, em 2026, não é mais "quem escreveu" — porque a IA escreveu boa parte das duas. A diferença é quem auditou depois.
Roda as ferramentas. Olha o resultado. Conserta. Roda de novo.
E mantém o .env longe do webroot, pelo amor.
💬 Curtiu o artigo?
Se quiser uma versão técnica focada em uma dessas ferramentas, ou um post sobre pipelines de CI com gitleaks + semgrep + dependabot, comenta aí embaixo que eu escrevo.