skills/06-security-review/SKILL.md
Skill do Security Reviewer para auditoria de segurança e boas práticas. Use quando precisar revisar código para vulnerabilidades, validar implementação de auth, checar OWASP Top 10, revisar CORS/CSRF/XSS, garantir DRY e clean code, ou qualquer review de segurança. Trigger em: "segurança", "security review", "vulnerabilidade", "OWASP", "XSS", "CSRF", "CORS", "injection", "HttpOnly", "cookie seguro", "DRY", "code review", "boas práticas", "audit", "pentest", "sanitização".
npx skillsauth add felvieira/claude-skills-fv security-reviewInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
⚠ Esta é a SKILL 06 (playbook de segurança). Não confundir com o subagent
dev-team-kit-fv:security-auditor.
- Carregar este playbook:
Skill({ skill: "dev-team-kit-fv:06-security-review" })- Despachar subagent isolado (turno novo):
Agent({ subagent_type: "dev-team-kit-fv:security-auditor", ... })- Diferença:
policies/skills-vs-agents.md
O Security Reviewer é a última barreira antes do deploy. Nada vai pra produção sem passar por aqui.
Esta skill segue GLOBAL.md, policies/execution.md, policies/handoffs.md, policies/quality-gates.md, policies/token-efficiency.md, policies/stack-flexibility.md, policies/tool-safety.md e policies/evals.md.
Para checklists detalhados e exemplos de findings, consultar docs/skill-guides/security-review.md apenas quando necessario.
☐ Rotas protegidas exigem autenticação
☐ Autorização por role em cada endpoint
☐ Não expõe IDs sequenciais (usar UUID)
☐ Sem IDOR (Insecure Direct Object Reference)
☐ Rate limiting em endpoints sensíveis
☐ CORS configurado com origin específica (nunca '*' em produção)
Teste rápido: Trocar ID no request pra acessar recurso de outro user → deve retornar 403
☐ Senhas com bcrypt (cost factor >= 12)
☐ HTTPS obrigatório (HSTS header)
☐ Tokens JWT assinados com algoritmo forte (RS256 ou HS256 com secret longo)
☐ Refresh token é UUID opaco (não JWT)
☐ Dados sensíveis encriptados at rest
☐ Nunca logar dados sensíveis (senha, token, CPF, cartão)
☐ ORM usado para queries (Prisma = safe by default)
☐ Zero concatenação de strings em queries
☐ Inputs validados com Zod antes de chegar no banco
☐ Parametrized queries quando raw SQL é necessário
☐ NoSQL injection prevenido (se usar MongoDB)
☐ Fluxo de reset de senha seguro (token temporário, expira)
☐ Sem "security by obscurity"
☐ Rate limit em login (max 5 tentativas/min)
☐ Account lockout após N tentativas
☐ Captcha ou challenge em ações críticas
☐ Headers de segurança configurados (ver seção abaixo)
☐ Error messages não expõem stack traces em produção
☐ Debug mode desligado em produção
☐ Portas desnecessárias fechadas
☐ Versão do Node/framework não tem CVEs conhecidas
☐ .env NUNCA no git (está no .gitignore)
☐ npm audit sem HIGH/CRITICAL
☐ Dependabot ou Snyk configurado
☐ Lock file (package-lock.json) commitado
☐ Não usa pacotes abandonados (última atualização > 2 anos)
☐ JWT access token curto (15 min máx)
☐ Refresh token em HttpOnly cookie
☐ Refresh token rotaciona a cada uso
☐ Logout invalida session no banco
☐ Não armazena token no localStorage (NUNCA)
☐ Cookie com flags: HttpOnly, Secure, SameSite=Strict
☐ CSP header configurado
☐ Subresource Integrity (SRI) em CDN scripts
☐ CI/CD pipeline tem testes de segurança
☐ Imagens Docker com hash fixo (não :latest)
☐ Logs de autenticação (login, logout, falhas)
☐ Logs de ações administrativas
☐ Logs não contêm dados sensíveis
☐ Alertas configurados para padrões suspeitos
☐ Request ID em cada log (traceability)
☐ URLs de input validadas contra whitelist
☐ Sem redirect baseado em parâmetro do usuário sem validação
☐ Metadata endpoint bloqueado (169.254.169.254)
src/middleware/security-headers.ts
export const securityHeaders = {
'X-Frame-Options': 'DENY',
'X-Content-Type-Options': 'nosniff',
'X-XSS-Protection': '0',
'Content-Security-Policy': [
"default-src 'self'",
"script-src 'self' 'unsafe-inline'",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: https:",
"font-src 'self'",
"connect-src 'self' https://api.seudominio.com",
"frame-ancestors 'none'",
"base-uri 'self'",
"form-action 'self'",
].join('; '),
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload',
'Referrer-Policy': 'strict-origin-when-cross-origin',
'Permissions-Policy': 'camera=(), microphone=(), geolocation=()',
};
next.config.js
const securityHeaders = [
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
];
module.exports = {
async headers() {
return [{ source: '/:path*', headers: securityHeaders }];
},
};
Inseguro:
app.use(cors());
Seguro:
app.use(cors({
origin: process.env.ALLOWED_ORIGINS?.split(',') || ['https://app.seudominio.com'],
credentials: true,
methods: ['GET', 'POST', 'PATCH', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-CSRF-Token'],
maxAge: 86400,
}));
import crypto from 'crypto';
export const generateCsrfToken = () => crypto.randomBytes(32).toString('hex');
export const csrfProtection = (req, res, next) => {
if (['GET', 'HEAD', 'OPTIONS'].includes(req.method)) return next();
const token = req.headers['x-csrf-token'];
const cookieToken = req.cookies['csrf-token'];
if (!token || !cookieToken || token !== cookieToken) {
return res.status(403).json({
success: false,
error: { code: 'CSRF_INVALID', message: 'CSRF token inválido' },
});
}
next();
};
app.get('/api/csrf-token', (req, res) => {
const token = generateCsrfToken();
res.cookie('csrf-token', token, {
httpOnly: false,
secure: true,
sameSite: 'strict',
maxAge: 3600000,
});
res.json({ token });
});
import DOMPurify from 'dompurify';
const clean = DOMPurify.sanitize(dirtyHTML);
const isValidUrl = (url: string) => {
try {
const parsed = new URL(url);
return ['http:', 'https:'].includes(parsed.protocol);
} catch {
return false;
}
};
Princípio DRY (Don't Repeat Yourself):
☐ Sem código duplicado — se algo aparece 2+ vezes, extrair pra função/hook/componente
☐ Constantes mágicas extraídas pra arquivo de constants
☐ Validations reutilizadas (Zod schemas compartilhados)
☐ API patterns seguem o hook genérico (useApiMutation, usePaginatedQuery)
☐ Stores seguem factory pattern (createStore)
☐ Error handling centralizado (middleware, não try/catch em cada rota)
☐ Types inferidos quando possível (z.infer, ReturnType, etc.)
Princípio SOLID:
☐ S — Cada módulo/função faz UMA coisa
☐ O — Extensível sem modificar código existente
☐ L — Componentes substituíveis (respeita interface/props)
☐ I — Interfaces pequenas e específicas
☐ D — Depende de abstrações, não implementações
Clean Code:
☐ Nomes descritivos (sem 'data', 'info', 'temp', 'handler' genéricos)
☐ Funcoes com tamanho proporcional e responsabilidade unica
☐ Comentarios apenas quando explicam contexto nao obvio, risco ou workaround
☐ Sem TODO esquecido — resolver ou criar issue
☐ Sem console.log em produção (usar logger estruturado)
☐ Sem any no TypeScript (exceto pontos de integração com libs sem tipo)
☐ Imports organizados (external → internal → relative)
Após review, gerar relatório:
# Security Review Report — [Feature Name]
**Data:** [data]
**Reviewer:** [nome]
**Status:** ✅ Aprovado / ⚠️ Aprovado com ressalvas / ❌ Reprovado
## Resumo
[1-2 frases]
## Findings
### 🔴 Crítico
- [descrição + localização + fix sugerido]
### 🟡 Importante
- [descrição + localização + fix sugerido]
### 🔵 Informativo
- [descrição + sugestão]
## Checklist
- [x] OWASP Top 10 verificado
- [x] Headers de segurança
- [x] Auth flow review
- [x] DRY review
- [x] npm audit clean
- [x] .env não exposto
## Decisão
[Aprovado/Reprovado] — [justificativa]
npm audit fix ou override em package.jsonPara output estruturado e persona detalhada com scopes de auditoria, severity labels, PoC requirements e template de relatório, ver personas/security-auditor.md.
Só libera se:
Codigo deve priorizar clareza. Comentarios so fazem sentido quando explicam contexto nao obvio, restricoes externas ou workarounds temporarios.
Se você reconhece um desses pensamentos, PARE e siga o processo. Ver policies/anti-rationalization.md.
| Racionalização | Realidade | |---|---| | "É só código interno, não precisa de segurança" | Lateralização de ataque vem de código interno. Interno ≠ seguro | | "Não tem input do usuário aqui" | Input vem de APIs, DBs, configs, env vars — não só de forms | | "Vou hardcodar temporário" | "Temporário" no código vive pra sempre. Secrets hardcoded são CVEs | | "Escopo é muito pequeno pra ter vulnerabilidade" | SQLi precisa de 1 linha. XSS precisa de 1 linha. Tamanho é irrelevante | | "Já passou no linter de segurança" | Linters pegam patterns conhecidos. Lógica de negócio insegura passa limpa |
testing
Skill do Product Owner para especificação de features. Use quando precisar definir requisitos de negócio, escrever user stories, critérios de aceitação, priorização de backlog, ou qualquer documento de especificação de produto. Inclui fundamento de negócio para discovery: validação de hipótese, problema vs. necessidade, MVP, modelo de monetização e métricas pirata (AARRR) como input da spec. Trigger em: "nova feature", "especificação", "user story", "requisito", "backlog", "PO", "definir escopo", "critério de aceitação", "MVP", "roadmap", "validação de hipótese", "discovery", "monetização", "pricing", "product-market fit", "métricas AARRR".
development
Skill compositora que pega texto/assunto e gera post de blog HTML completo no repo {blog_repo_path} ({github_user_repo_url}), com imagens (via skill 17 fal.ai ou skill 42 Playwright screenshot), commit+push automático, retorna URL pública via GitHub Pages. Trigger em: "post no blog", "publicar post", "escrever post", "blog post", "publish blog", "gera post", "criar post", "novo post no meu blog".
tools
Audita o peso de contexto carregado na sessão — CLAUDE.md, agents, MCP descriptions, rules ativas, skills invocadas e histórico acumulado. Estima tokens por componente, reporta headroom disponível e emite alertas de overflow. Distinto do cost-tracker (skill 30) que rastreia tokens gastos em completions runtime. Trigger em: "contexto inchado", "context overflow", "quanto contexto estou usando", "peso do contexto", "context budget", "tokens carregados", "sessao lenta", "respostas degradadas", "headroom de contexto", "custo fixo de contexto", "overhead de rules", "overhead dos agents", "impacto do MCP no contexto", "espaco no context window", "quanto cabe no context window"
development
Coleta e organiza informacao tecnica multi-fonte antes de escrever docs, PRDs, ADRs ou artigos. Busca em: docs oficiais, GitHub (repos + issues), Stack Overflow, papers e blogs de referencia. Ranqueia fontes por autoridade (oficial 40% + recencia 30% + profundidade 20% + comunidade 10%). Output: memory/research/<slug>.md pronto para alimentar skill 10 (documenter), skill 01 (po-feature-spec), skill 26 (prompt-engineer) ou skill 41 (blog-publisher). Trigger em: "pesquisa tecnica", "levanta informacao", "coleta docs", "busca referencias", "preciso de fontes", "research antes de escrever", "levanta o que existe sobre", "benchmark de solucoes", "o que existe sobre X", "quero entender o estado da arte", "compara abordagens", "levanta referencias", "faz um research de", "coleta fontes sobre", "pesquisa sobre", "quero saber o que existe de", "monta um dossie tecnico", "background tecnico", "due diligence tecnica", "levantamento de alternativas".