Ler código gerado: como auditar diff, red flags, segurança, performance
4 min de leitura
Você aceitou um diff de 200+ linhas que IA gerou. Funciona (testes passam). Manda pro PR. Aí vem o reviewer: "isso aqui tem 3 problemas de segurança". Esse nó cobre como auditar código gerado por IA - checklist de red flags, patterns de segurança, performance, e como não cair em armadilhas.
IA gera código que parece certo mas tem falhas sutis: SQL injection, XSS, algoritmo O(n²) em vez de O(n log n), dependencies desatualizadas com CVE. Sem revisar, você herda a vulnerabilidade. Review não é opcional.
Você sai de "aceito código gerado" pra "aceito depois de auditar com checklist".
O essencial 🟢
O checklist dos 7 red flags. Antes de aceitar diff gerado por IA, rode este checklist:
- Segurança: SQL injection? XSS? CSRF? Secret hardcoded?
- Input validation: Inputs são validados (zod, yup, io-ts)?
- Auth/authz: Permissoes verificadas? Token validado?
- Error handling: Try/catch adequado? Errors não silenciosos?
- Performance: O(n²) em vez de O(n)? Loop aninhado desnecessário? Memory leak (setInterval não cleared)?
- Dependencies: Pkg novo? CVE conhecido? Licença OK?
- Edge cases: null/undefined? array vazio? string vazia? número negativo? Unicode?
Cada item = 1-2 min de review. Total: 10-15 min por PR de 200 linhas. Vale a pena.
Os 3 bugs de segurança mais comuns em código gerado por IA.
-
SQL injection. IA gera query com template literal.
// ❌ Vulnerável const user = await db.query( `SELECT * FROM users WHERE id = ${userId}` ); // ✅ Seguro const user = await db.query( "SELECT * FROM users WHERE id = $1", [userId] ); -
XSS (Cross-Site Scripting). IA gera render sem escape.
// ❌ Vulnerável <div dangerouslySetInnerHTML={{ __html: userInput }} /> // ✅ Seguro <div>{userInput}</div> // React escapa automático -
Secret hardcoded. IA gera código com credenciais.
// ❌ Vulnerável const apiKey = "sk-abc123hardcoded"; // ✅ Seguro const apiKey = process.env.OPENAI_API_KEY;
Checklist de performance.
- Big O: loop dentro de loop = O(n²). Hash map / Set para lookup O(1).
- Memory:
setIntervalnão cleaned,addEventListenernão removed, referência circular. - Network: N+1 queries, falta cache, falta de paginação.
- Render: re-render desnecessário (React), loop gigante no template.
Checklist de edge cases.
- null / undefined
- array vazio []
- string vazia ""
- número 0
- número negativo
- NaN, Infinity
- Unicode (emoji, RTL)
- timezone (UTC vs local)
- locale (pt-BR vs en-US)
- input muito grande (>1MB)
- concurrent updates
O pattern: "trust but verify". IA gera código que parece correto. Você verifica com:
- Ler o diff (não aceitar sem ler).
- Rodar testes (IA gera teste? Confia? Escreve o seu).
- Type check (TypeScript salva).
- Lint (ESLint/Biome pega patterns ruins).
- Code review (1 outro humano revisa).
- Test em prod (canary, feature flag, monitor).
Como ler um diff grande (200+ linhas) eficientemente. Não leia linha por linha. Estratégia:
- Visão geral: olhe a estrutura (quais arquivos? quais funções novas? quais deletadas?).
- Pontos de entrada:
main,index, exports públicos. - Lógica nova: funções/classes adicionadas (diff +).
- Mudanças críticas: arquivos de segurança (auth, payment, API routes).
- Testes: novos testes = bom sinal. Testes mudados sem justificativa = red flag.
Ferramentas de audit.
git diff --stat: visão geral do tamanho.git diff --check: warnings de whitespace.- CodeQL (GitHub): scan automático de segurança no PR.
- Snyk / Dependabot: scan de vulnerabilities em dependencies.
- ESLint + plugins: patterns ruins (security, performance).
- Semgrep: static analysis customizável.
Checklist de dependencies.
# Pkg novo adicionado
git diff package.json
# Pergunte:
# 1. Esse pkg é necessário? (N+1 deps)
# 2. Tem CVE conhecido? (npm audit)
# 3. Licença compatível? (MIT, Apache, etc)
# 4. Maintainer ativo? (último commit)
# 5. Bundle size? (bundlephobia)
# 6. Alternatives? (mature, popular)
O erro mais comum: aceitar código de IA "porque funciona". "Funciona" não significa "correto". Funciona no caminho feliz. Falha em: segurança, performance, edge cases, acessibilidade. Audit antes de aceitar.
Checklist visual de código aceitável.
[ ] Lido TODO o diff (não skim)
[ ] Sem SQL injection (queries parametrizadas)
[ ] Sem XSS (escape user input)
[ ] Sem secret hardcoded (env vars)
[ ] Inputs validados (zod, yup)
[ ] Error handling adequado (try/catch + log)
[ ] Performance O(n) ou O(n log n), não O(n^2)
[ ] Memory: intervals/listeners cleaned
[ ] Edge cases: null, vazio, Unicode
[ ] Tests: novos testes OU testes existentes passam
[ ] Type check: 0 erros
[ ] Lint: 0 errors
[ ] Dependencies: 0 CVEs (npm audit)
[ ] Accessibility: ARIA, contraste, keyboard
[ ] License: MIT/Apache, não GPL em projeto proprietário
Aprofundamento 🟡
Diff de 200+ linhas: como revisar sem perder detalhe. Estrategia 3-pass:
-
Pass 1 - Contexto (5 min):
git diff --stat, leia commit message, leia descrição do PR. Entenda a intenção antes de auditar código. -
Pass 2 - Hot paths (10 min): Foque em security-critical: auth, payment, API routes, file upload, query strings, eval/Function. CodeQL ou Semgrep scan automático aqui.
-
Pass 3 - Logic (15 min): Foque em lógica nova (funções adicionadas) e mudanças em funções existentes (refactor). Rode testes local. Type check.
Total: 30 min por PR grande. Vs 10 min pra PR pequeno. Trade-off aceitável.
Como auditar código de auth especificamente. Red flags específicos:
// 1. Token em localStorage (XSS rouba)
localStorage.setItem("token", jwt); // ❌
// 2. Auth check no client (bypass)
if (user.role === "admin") showAdminPanel(); // ❌
// 3. JWT sem verificar signature
const user = jwt.decode(token); // ❌
const user = jwt.verify(token, SECRET); // ✅
// 4. Permissoes baseadas em user.id
if (req.params.id === user.id) updateUser(); // ❌ race condition
// ✅ Server-side: verificar role + ownership
Como auditar código de payment.
// 1. Trust no client-side price
const amount = req.body.amount; // ❌ user manipula
const amount = product.price; // ✅ server-side lookup
// 2. Idempotency ausente
if (!paymentExists(orderId)) {
await charge(orderId);
} // ❌ double charge em retry
// ✅ Use idempotency key
// 3. Amount sem validar
if (amount > 0) charge(amount); // ❌
if (amount > 0 && amount < MAX_AMOUNT) charge(amount); // ✅
CodeQL e Semgrep. Ferramentas static analysis que rodam no PR (GitHub Actions) e acham bugs conhecidos:
# GitHub Actions
- uses: github/codeql-action/analyze@v2
with:
languages: javascript
CodeQL acha SQL injection, XSS, path traversal, unsafe deserialization. Semgrep é customizável (rules escritas em YAML).
AI auditor: 2-pass com 2 LLMs. Pattern: LLM A gera código, LLM B revisa (Claude gera, GPT revisa, ou vice-versa). Bugs que LLM A perdeu (por ser o autor) são pegos por LLM B (sem viés de autor). Em 2026, +30% bugs pegos com 2-pass vs 1.
Leitura recomendada:
- OWASP - Top 10 LLM - top vulnerabilidades de LLM apps (LLM01-LLM10).
- GitHub - Code Review Guide - como revisar PR.
Dica: o erro mais comum em AI coding é aceitar código sem auditar. "Funciona" != "correto". 10-15 min de checklist por PR grande = evita SQL injection, XSS, O(n²), secret hardcoded. IA gera 80% do código, você audita 20% - a parte crítica é a auditoria. Sem audit, IA é vetor de ataque: o atacante manipula o prompt ou explora alucinação conhecida (lib inexistente, CVE). Audit é obrigatório.
No próximo nó, vamos IA no test: como gerar testes com IA, validar que não são teatro (testa "implementação" mas não lógica), e garantir que testes pegam bugs reais.
// Quiz
Qual o erro mais comum ao aceitar código gerado por IA e como evitar?