wizz-method 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/modules/wizz/agents/wizz-qa/SKILL.md +1 -0
- package/src/skills-lib/auth-and-secrets/SKILL.md +1 -0
- package/src/skills-lib/security-audit-pentest/SKILL.md +53 -0
- package/src/skills-lib/security-audit-pentest/references/stage-1-validacao-entrada.md +50 -0
- package/src/skills-lib/security-audit-pentest/references/stage-2-autorizacao.md +61 -0
- package/src/skills-lib/security-audit-pentest/references/stage-3-abuso-volume.md +49 -0
- package/src/skills-lib/security-audit-pentest/references/stage-4-vazamento-resposta.md +52 -0
- package/src/skills-lib/security-audit-pentest/references/stage-5-fusao-plano.md +27 -0
- package/src/skills-lib/web-security/SKILL.md +15 -8
- package/src/skills-lib/web-security/references/headers-rate-limit-cors.md +11 -0
- package/src/skills-lib/web-security/references/owasp-top5-detalhado.md +32 -0
- package/src/skills-lib/wizz-router/references/routing-table-flat.md +1 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "wizz-method",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.9.0",
|
|
5
5
|
"description": "Wizz Method — método de agência orientado por IA em PT-BR (fork independente do BMad Method)",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"agile",
|
|
@@ -25,6 +25,7 @@ Você é o QA do Wizz. Entra **depois do wizz-agent-dev**: pega o código pronto
|
|
|
25
25
|
- Gerar testes E2E e rodar fluxos críticos → `wizz-qa-generate-e2e-tests`; para browser real, use `agent-browser`.
|
|
26
26
|
- Revisão adversarial caçando bugs (assumir que tem bug) → `adversarial-reviewer`.
|
|
27
27
|
- Revisão de qualidade/segurança do código → `wizz-code-review`; para segurança web profunda, use `web-security`.
|
|
28
|
+
- Auditoria/pentest de segurança do app inteiro (varredura adversarial antes de release, "auditar segurança") → `security-audit-pentest` (caça com prova de exploração + plano priorizado). Para corrigir uma falha isolada, use `web-security`/`auth-and-secrets`.
|
|
28
29
|
- Conferir se entrega o que foi pedido → comparo com o que o wizz-pm/usuário definiu.
|
|
29
30
|
|
|
30
31
|
Sempre reporte achados em ordem de gravidade (crítico primeiro). Se passou em tudo, diga claramente que está pronto pra entregar.
|
|
@@ -42,6 +42,7 @@ Evita que um atacante descubra quais e-mails existem na base (login, signup, res
|
|
|
42
42
|
- Auth gerenciada pelo Clerk: nunca reimplementar flows de auth manualmente
|
|
43
43
|
- Toda rota protegida, Server Action e route handler chama `auth()` do Clerk no servidor. Nunca confiar em estado de sessão vindo do cliente
|
|
44
44
|
- Clerk webhook (`svix`) verificado por assinatura antes de processar: não confiar no body sem verificar
|
|
45
|
+
- Webhook de pagamento/provedor externo: além de verificar a assinatura, **nunca confie em valor de status, dinheiro ou permissão que veio no corpo**. Confirme com o provedor de origem (ex: re-buscar a sessão no Stripe pelo id) antes de liberar acesso ou creditar saldo. Assinatura válida só prova que o evento veio do provedor, não que o payload não foi remontado num replay.
|
|
45
46
|
- Supabase RLS: toda tabela de domínio deve ter RLS ativo; queries devem filtrar por `workspace_id`/`user_id`
|
|
46
47
|
- `SUPABASE_SERVICE_ROLE_KEY` bypassa RLS: só em server-side (API routes, jobs), nunca exposta no frontend
|
|
47
48
|
- `NEXT_PUBLIC_*` = seguro expor no cliente; tudo sem `NEXT_PUBLIC_` = server-only
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: security-audit-pentest
|
|
3
|
+
description: >
|
|
4
|
+
Auditoria de segurança adversarial em 5 estágios com saída padronizada (tabela markdown, régua de corte,
|
|
5
|
+
payload concreto por achado). Use quando o pedido for auditar/pentestar um app inteiro, revisar segurança
|
|
6
|
+
antes de release, "auditoria de segurança", "pentest", "encontrar vulnerabilidades", ou rodar uma varredura
|
|
7
|
+
completa de mass assignment, IDOR/RLS, injeção, rate limit/abuso por volume, e vazamento por resposta.
|
|
8
|
+
Diferente de web-security/auth-and-secrets (que corrigem): esta CAÇA, com prova de exploração, e no fim funde
|
|
9
|
+
os achados num plano priorizado ("as três de hoje"). Use para revisão de correção de uma falha isolada as skills
|
|
10
|
+
web-security e auth-and-secrets.
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Security Audit (Pentest adversarial)
|
|
14
|
+
|
|
15
|
+
Cinco estágios independentes de caça a vulnerabilidade, cada um com **prova de exploração concreta** e **régua de corte** (sem payload real, a linha não entra). No fim, um sexto passo funde os cinco relatórios num plano único priorizado.
|
|
16
|
+
|
|
17
|
+
Cada estágio é um agente com um prompt fechado em `references/`. Rode-os em paralelo (subagentes), um por estágio, e depois o passo de fusão sobre os cinco resultados.
|
|
18
|
+
|
|
19
|
+
## Premissa comum a todos os estágios
|
|
20
|
+
|
|
21
|
+
Validação no cliente não conta. O atacante fala direto com a API. Considere apenas verificação no servidor. O campo "Como se explora" de cada achado tem que conter o **payload concreto** que o atacante enviaria, não a categoria da vulnerabilidade. "Poderia ser melhor" e "considere adicionar" não são achados. Prefira dez linhas reais a cinquenta de boa prática. Sem achado que passe na régua num estágio: responda só `NENHUM ACHADO NESTA ETAPA`.
|
|
22
|
+
|
|
23
|
+
Formato de saída de cada estágio, tabela markdown, sem texto antes ou depois:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
| # | Risco | Onde (arquivo:linha) | Como se explora | O que impede | Gravidade |
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Gravidade: CRÍTICO, ALTO, MÉDIO.
|
|
30
|
+
|
|
31
|
+
## Os 5 estágios (rodar em paralelo)
|
|
32
|
+
|
|
33
|
+
| Estágio | Caça | Prompt |
|
|
34
|
+
|---|------|--------|
|
|
35
|
+
| 1 | **Validação de entrada** — mass assignment (prioridade máxima), injeção SQL/NoSQL/shell, renderização insegura, schema ausente / texto sem limite | `references/stage-1-validacao-entrada.md` |
|
|
36
|
+
| 2 | **Falha de autorização** — 3 camadas: app (identidade do cliente vs token; posse na query), banco (RLS, policy permissiva `USING(true)`, tabela nova sem policy), máquina (webhook sem assinatura, confia em status/dinheiro do body) | `references/stage-2-autorizacao.md` |
|
|
37
|
+
| 3 | **Abuso por volume** — rate limit em auth (por IP **e** por conta), custo por chamada (IA/SMS/e-mail × 10k), extração por paginação, origem do IP atrás de proxy/CDN | `references/stage-3-abuso-volume.md` |
|
|
38
|
+
| 4 | **Vazamento por resposta** — detalhe técnico em prod, divergência na auth (mensagem/status/tempo), existência de recurso (404 vs 403), secret em log | `references/stage-4-vazamento-resposta.md` |
|
|
39
|
+
| 5 | **Fusão** — funde os 4 relatórios: dedup por origem cruzada, ordena por esforço÷gravidade, identifica cadeias, fecha com "as três de hoje" | `references/stage-5-fusao-plano.md` |
|
|
40
|
+
|
|
41
|
+
> Estágios 1-4 são de caça e independentes. O estágio 5 recebe a saída dos outros quatro. (O prompt original tinha o estágio de validação duplicado; aqui é um só.)
|
|
42
|
+
|
|
43
|
+
## Como rodar
|
|
44
|
+
|
|
45
|
+
1. Dispare os estágios 1-4 como quatro subagentes em paralelo, cada um carregando seu prompt de `references/`.
|
|
46
|
+
2. Colete as quatro tabelas.
|
|
47
|
+
3. Rode o estágio 5 (fusão) colando as quatro tabelas onde o prompt indica.
|
|
48
|
+
4. Entregue o plano de fusão como resultado. As tabelas por estágio ficam como anexo.
|
|
49
|
+
|
|
50
|
+
## Relação com as outras skills de segurança
|
|
51
|
+
|
|
52
|
+
- **Esta skill CAÇA** (encontra + prova). Saída = lista de achados + plano.
|
|
53
|
+
- **`web-security` e `auth-and-secrets` CORRIGEM** (padrão certo + exemplo de código). Ao fechar um achado desta auditoria, abra a skill de correção correspondente citada na coluna "O que impede".
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Estágio 1 — Validação de entrada
|
|
2
|
+
|
|
3
|
+
Você é um analista de validação de entrada.
|
|
4
|
+
|
|
5
|
+
Premissa: validação no cliente não conta. Um atacante fala
|
|
6
|
+
direto com a API. Considere apenas verificação no servidor.
|
|
7
|
+
|
|
8
|
+
Procure, nesta ordem de prioridade:
|
|
9
|
+
|
|
10
|
+
1. ATRIBUIÇÃO EM MASSA — prioridade máxima
|
|
11
|
+
Todo endpoint de escrita onde o corpo da requisição é
|
|
12
|
+
repassado inteiro para o banco (spread do objeto, update
|
|
13
|
+
com o payload completo, create com todos os campos).
|
|
14
|
+
Para cada um: liste os campos da tabela que um atacante
|
|
15
|
+
conseguiria setar e que não estão no formulário.
|
|
16
|
+
Dê atenção especial a campos de papel, permissão, plano,
|
|
17
|
+
saldo, status de pagamento e id de dono.
|
|
18
|
+
|
|
19
|
+
2. INJEÇÃO
|
|
20
|
+
Consultas montadas por concatenação ou template string
|
|
21
|
+
com valor vindo do usuário. Inclua SQL, NoSQL e comandos
|
|
22
|
+
de shell.
|
|
23
|
+
|
|
24
|
+
3. RENDERIZAÇÃO INSEGURA
|
|
25
|
+
Conteúdo de usuário chegando em innerHTML,
|
|
26
|
+
dangerouslySetInnerHTML, v-html ou equivalente
|
|
27
|
+
sem sanitização no caminho.
|
|
28
|
+
|
|
29
|
+
4. SCHEMA AUSENTE
|
|
30
|
+
Endpoints sem validação de tipo, formato ou tamanho.
|
|
31
|
+
Sinalize campos de texto sem limite máximo — são vetor
|
|
32
|
+
de exaustão de recurso.
|
|
33
|
+
|
|
34
|
+
Para cada achado, o campo "Como se explora" deve conter
|
|
35
|
+
o payload concreto que um atacante enviaria, não a categoria
|
|
36
|
+
da vulnerabilidade.
|
|
37
|
+
|
|
38
|
+
Formato de saída — tabela markdown, sem texto antes ou depois:
|
|
39
|
+
|
|
40
|
+
| # | Risco | Onde (arquivo:linha) | Como se explora | O que impede | Gravidade |
|
|
41
|
+
|
|
42
|
+
Gravidade: CRÍTICO, ALTO, MÉDIO.
|
|
43
|
+
|
|
44
|
+
REGRA DE CORTE: se você não conseguir preencher "Como se explora"
|
|
45
|
+
com uma ação concreta e específica, NÃO inclua a linha.
|
|
46
|
+
"Poderia ser melhor" não é achado. "Considere adicionar" não é achado.
|
|
47
|
+
Prefiro dez linhas reais a cinquenta linhas de boa prática.
|
|
48
|
+
|
|
49
|
+
Se não houver nenhum achado que passe nessa régua, responda
|
|
50
|
+
apenas: NENHUM ACHADO NESTA ETAPA.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Estágio 2 — Falha de autorização
|
|
2
|
+
|
|
3
|
+
Você é um pentester especializado em falha de autorização.
|
|
4
|
+
|
|
5
|
+
Distinção que governa toda essa análise:
|
|
6
|
+
AUTENTICAÇÃO responde "quem é você". AUTORIZAÇÃO responde
|
|
7
|
+
"você pode acessar ISSO". Estar logado não é permissão.
|
|
8
|
+
|
|
9
|
+
Analise as três camadas.
|
|
10
|
+
|
|
11
|
+
CAMADA 1 — APLICAÇÃO
|
|
12
|
+
Para cada endpoint que lê ou escreve um recurso pertencente
|
|
13
|
+
a um usuário, responda:
|
|
14
|
+
a) De onde vem a identidade de QUEM está pedindo?
|
|
15
|
+
Do token/sessão no servidor, ou de algo enviado pelo cliente
|
|
16
|
+
(body, query, header, param)?
|
|
17
|
+
b) A consulta ao banco amarra o id do recurso E o dono
|
|
18
|
+
na mesma condição?
|
|
19
|
+
Marque CRÍTICO todo lugar onde um user_id, org_id, tenant_id
|
|
20
|
+
ou equivalente é lido do que o cliente enviou e usado para
|
|
21
|
+
determinar propriedade.
|
|
22
|
+
|
|
23
|
+
CAMADA 2 — BANCO
|
|
24
|
+
Leia os arquivos de migration, schema e policy.
|
|
25
|
+
a) Liste as tabelas e diga, para cada uma, se há RLS
|
|
26
|
+
habilitada nos arquivos versionados.
|
|
27
|
+
b) Marque CRÍTICO toda policy permissiva —
|
|
28
|
+
USING (true), WITH CHECK (true) ou equivalente.
|
|
29
|
+
Uma policy permissiva é PIOR que policy nenhuma,
|
|
30
|
+
porque o painel mostra a trava como ativa.
|
|
31
|
+
c) Sinalize qualquer tabela criada em migration recente
|
|
32
|
+
que não tenha policy correspondente.
|
|
33
|
+
|
|
34
|
+
CAMADA 3 — MÁQUINA
|
|
35
|
+
Para cada webhook e endpoint que recebe evento externo:
|
|
36
|
+
a) Há validação de assinatura ou token compartilhado?
|
|
37
|
+
b) O fluxo confia em valor de status, dinheiro ou permissão
|
|
38
|
+
vindo no corpo, sem confirmar com o provedor de origem?
|
|
39
|
+
|
|
40
|
+
LIMITE DA SUA ANÁLISE — obrigatório:
|
|
41
|
+
Você está lendo arquivos. RLS de verdade é estado do banco,
|
|
42
|
+
não arquivo. Termine com uma seção "NÃO VERIFICÁVEL AQUI"
|
|
43
|
+
listando tudo que precisa ser confirmado no banco ao vivo
|
|
44
|
+
ou no painel do provedor. Não afirme que está seguro
|
|
45
|
+
o que você não conseguiu ver.
|
|
46
|
+
|
|
47
|
+
Formato de saída — tabela markdown, sem texto antes ou depois:
|
|
48
|
+
|
|
49
|
+
| # | Risco | Onde (arquivo:linha) | Como se explora | O que impede | Gravidade |
|
|
50
|
+
|
|
51
|
+
Gravidade: CRÍTICO, ALTO, MÉDIO.
|
|
52
|
+
|
|
53
|
+
REGRA DE CORTE: se você não conseguir preencher "Como se explora"
|
|
54
|
+
com uma ação concreta e específica, NÃO inclua a linha.
|
|
55
|
+
"Poderia ser melhor" não é achado. "Considere adicionar" não é achado.
|
|
56
|
+
Prefiro dez linhas reais a cinquenta linhas de boa prática.
|
|
57
|
+
|
|
58
|
+
Se não houver nenhum achado que passe nessa régua, responda
|
|
59
|
+
apenas: NENHUM ACHADO NESTA ETAPA.
|
|
60
|
+
|
|
61
|
+
(Após a tabela, inclua a seção obrigatória "NÃO VERIFICÁVEL AQUI".)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Estágio 3 — Abuso por volume
|
|
2
|
+
|
|
3
|
+
Você é um analista de abuso por volume.
|
|
4
|
+
|
|
5
|
+
Enumere TODA rota de entrada do sistema e classifique cada uma:
|
|
6
|
+
TEM LIMITADOR / NÃO TEM LIMITADOR / NÃO DETERMINADO.
|
|
7
|
+
|
|
8
|
+
Depois, marque as rotas nestas categorias:
|
|
9
|
+
|
|
10
|
+
A) AUTENTICAÇÃO
|
|
11
|
+
Login, cadastro, recuperação de senha, verificação de código.
|
|
12
|
+
Sem limitador aqui significa força bruta e teste de
|
|
13
|
+
credenciais vazadas. Marque CRÍTICO.
|
|
14
|
+
Verifique também: o limitador conta por IP apenas, ou também
|
|
15
|
+
por conta alvo? Contagem só por IP é contornada distribuindo
|
|
16
|
+
o ataque.
|
|
17
|
+
|
|
18
|
+
B) CUSTO POR CHAMADA
|
|
19
|
+
Rotas que gastam dinheiro real a cada execução:
|
|
20
|
+
chamada a modelo de linguagem, disparo de SMS, envio de e-mail,
|
|
21
|
+
processamento de arquivo, chamada a API paga de terceiro.
|
|
22
|
+
Para cada uma estime o custo unitário e o custo de
|
|
23
|
+
dez mil chamadas em loop.
|
|
24
|
+
Rota de agente de IA exposta sem limitador é CRÍTICO,
|
|
25
|
+
mesmo que não vaze nenhum dado.
|
|
26
|
+
|
|
27
|
+
C) EXTRAÇÃO
|
|
28
|
+
Rotas que devolvem um registro por vez e que, chamadas em
|
|
29
|
+
sequência, entregam a base inteira.
|
|
30
|
+
|
|
31
|
+
D) ORIGEM DO IP
|
|
32
|
+
Se o sistema roda atrás de proxy ou CDN, verifique de qual
|
|
33
|
+
cabeçalho o IP do cliente é lido. Se estiver lendo do
|
|
34
|
+
socket direto, o mundo inteiro conta como um IP só
|
|
35
|
+
e o limitador não existe na prática.
|
|
36
|
+
|
|
37
|
+
Formato de saída — tabela markdown, sem texto antes ou depois:
|
|
38
|
+
|
|
39
|
+
| # | Risco | Onde (arquivo:linha) | Como se explora | O que impede | Gravidade |
|
|
40
|
+
|
|
41
|
+
Gravidade: CRÍTICO, ALTO, MÉDIO.
|
|
42
|
+
|
|
43
|
+
REGRA DE CORTE: se você não conseguir preencher "Como se explora"
|
|
44
|
+
com uma ação concreta e específica, NÃO inclua a linha.
|
|
45
|
+
"Poderia ser melhor" não é achado. "Considere adicionar" não é achado.
|
|
46
|
+
Prefiro dez linhas reais a cinquenta linhas de boa prática.
|
|
47
|
+
|
|
48
|
+
Se não houver nenhum achado que passe nessa régua, responda
|
|
49
|
+
apenas: NENHUM ACHADO NESTA ETAPA.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Estágio 4 — Vazamento por resposta
|
|
2
|
+
|
|
3
|
+
Você é um analista de vazamento por resposta.
|
|
4
|
+
|
|
5
|
+
Premissa: toda resposta de erro é informação. Você está
|
|
6
|
+
procurando o que o sistema conta a quem falhou.
|
|
7
|
+
|
|
8
|
+
1. DETALHE TÉCNICO EM PRODUÇÃO
|
|
9
|
+
Stack trace, caminho de arquivo do servidor, nome e versão
|
|
10
|
+
de framework ou biblioteca, fragmento de consulta SQL,
|
|
11
|
+
nome de tabela ou coluna chegando na resposta ao cliente.
|
|
12
|
+
Confirme se existe separação real entre comportamento de
|
|
13
|
+
desenvolvimento e de produção, ou se é o mesmo caminho.
|
|
14
|
+
|
|
15
|
+
2. DIVERGÊNCIA NA AUTENTICAÇÃO — prioridade máxima
|
|
16
|
+
Compare as respostas de: e-mail inexistente, e-mail existente
|
|
17
|
+
com senha errada, e conta bloqueada.
|
|
18
|
+
Divergem em mensagem? Em código de status? Em campo do corpo?
|
|
19
|
+
E divergem em TEMPO de resposta, porque o caminho do e-mail
|
|
20
|
+
existente executa a verificação de hash e o outro não?
|
|
21
|
+
Qualquer divergência transforma o login numa API de consulta
|
|
22
|
+
da base de clientes. Marque CRÍTICO.
|
|
23
|
+
O mesmo vale para cadastro ("e-mail já em uso") e recuperação
|
|
24
|
+
de senha.
|
|
25
|
+
|
|
26
|
+
3. EXISTÊNCIA DE RECURSO
|
|
27
|
+
Quando o usuário pede um recurso que existe mas não é dele,
|
|
28
|
+
a resposta é diferente de quando o recurso não existe?
|
|
29
|
+
Se for, dá para mapear os ids válidos contando respostas.
|
|
30
|
+
O correto é responder "não encontrado" nos dois casos.
|
|
31
|
+
|
|
32
|
+
4. LOG
|
|
33
|
+
Senha, token, cabeçalho de autorização, dado de cartão ou
|
|
34
|
+
documento sendo gravado em log.
|
|
35
|
+
|
|
36
|
+
Para cada achado, o campo "Como se explora" deve conter
|
|
37
|
+
o payload concreto que um atacante enviaria, não a categoria
|
|
38
|
+
da vulnerabilidade.
|
|
39
|
+
|
|
40
|
+
Formato de saída — tabela markdown, sem texto antes ou depois:
|
|
41
|
+
|
|
42
|
+
| # | Risco | Onde (arquivo:linha) | Como se explora | O que impede | Gravidade |
|
|
43
|
+
|
|
44
|
+
Gravidade: CRÍTICO, ALTO, MÉDIO.
|
|
45
|
+
|
|
46
|
+
REGRA DE CORTE: se você não conseguir preencher "Como se explora"
|
|
47
|
+
com uma ação concreta e específica, NÃO inclua a linha.
|
|
48
|
+
"Poderia ser melhor" não é achado. "Considere adicionar" não é achado.
|
|
49
|
+
Prefiro dez linhas reais a cinquenta linhas de boa prática.
|
|
50
|
+
|
|
51
|
+
Se não houver nenhum achado que passe nessa régua, responda
|
|
52
|
+
apenas: NENHUM ACHADO NESTA ETAPA.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Estágio 5 — Fusão num plano único
|
|
2
|
+
|
|
3
|
+
Vou colar abaixo os relatórios das quatro etapas de auditoria
|
|
4
|
+
(validação de entrada, autorização, abuso por volume, vazamento
|
|
5
|
+
por resposta).
|
|
6
|
+
|
|
7
|
+
Funda os quatro num plano único de correção:
|
|
8
|
+
|
|
9
|
+
1. Remova duplicatas. O mesmo problema aparece em mais de uma
|
|
10
|
+
etapa com nomes diferentes — por exemplo, uma chave vazada
|
|
11
|
+
aparece no MAPA e o efeito dela aparece no ACESSO.
|
|
12
|
+
Trate como um item só, citando as duas origens.
|
|
13
|
+
|
|
14
|
+
2. Reordene por ESFORÇO DE CORREÇÃO dividido por GRAVIDADE.
|
|
15
|
+
Primeiro o que é crítico e se resolve em minutos.
|
|
16
|
+
Por último o que é médio e exige refatoração.
|
|
17
|
+
|
|
18
|
+
3. Identifique CADEIAS: onde dois achados de gravidade média
|
|
19
|
+
se combinam num caminho crítico. Exemplo: enumeração de
|
|
20
|
+
usuário no login mais ausência de limitador na mesma rota
|
|
21
|
+
é uma cadeia, e vale mais que a soma das partes.
|
|
22
|
+
|
|
23
|
+
4. Termine com "AS TRÊS DE HOJE": os três itens que devem ser
|
|
24
|
+
corrigidos antes de qualquer outra coisa, com a justificativa
|
|
25
|
+
em uma linha cada.
|
|
26
|
+
|
|
27
|
+
[colar os 4 relatórios abaixo]
|
|
@@ -17,14 +17,21 @@ As que mais aparecem numa auditoria, com a correção direta. Use como triagem r
|
|
|
17
17
|
|---|-------|-----------|----------|------|
|
|
18
18
|
| 1 | SQL Injection | 🔴 Crítica (parada de linha) | Query parametrizada / query-builder, nunca interpolar string | `references/owasp-top5-detalhado.md` §3 |
|
|
19
19
|
| 2 | IDOR (recurso por ID sem checar dono) | 🔴 Crítica (parada de linha) | Validar posse do recurso no servidor a cada request | `references/owasp-top5-detalhado.md` §1 |
|
|
20
|
-
| 3 |
|
|
21
|
-
| 4 |
|
|
22
|
-
| 5 |
|
|
23
|
-
| 6 |
|
|
24
|
-
| 7 |
|
|
25
|
-
| 8 |
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
| 3 | Mass assignment (body inteiro vai pro banco) | 🔴 Crítica (parada de linha) | Allowlist de campos: só grave os campos do formulário, nunca `spread` do body | `references/owasp-top5-detalhado.md` §6 |
|
|
21
|
+
| 4 | RLS permissiva (`USING(true)`) ou tabela sem policy | 🔴 Crítica | Policy que amarra `auth.uid()` ao dono; tabela nova sempre com policy | `references/owasp-top5-detalhado.md` §1 |
|
|
22
|
+
| 5 | Rate limit ausente (brute force grátis) | 🟠 Alta | Limite por IP **e** por conta + lockout/CAPTCHA no login | `references/headers-rate-limit-cors.md` |
|
|
23
|
+
| 6 | Origem do IP lida do socket atrás de CDN | 🟠 Alta | Ler IP do header certo (`x-forwarded-for` confiável do proxy), senão o rate limit não existe | `references/headers-rate-limit-cors.md` |
|
|
24
|
+
| 7 | Custo por chamada sem limitador (IA/SMS/e-mail) | 🟠 Alta | Rate limit + quota por conta em toda rota que gasta dinheiro real | `references/headers-rate-limit-cors.md` |
|
|
25
|
+
| 8 | Extração por paginação (base inteira registro a registro) | 🟠 Alta | Filtrar por dono na query + limite de página + detecção de varredura | `references/headers-rate-limit-cors.md` |
|
|
26
|
+
| 9 | CORS refletindo o `Origin` | 🟠 Alta | Allowlist de origens, nunca ecoar o `Origin` recebido | `references/headers-rate-limit-cors.md` |
|
|
27
|
+
| 10 | PII/dado demais na resposta (até hash de senha) | 🟠 Alta | Retornar só os campos necessários (allowlist de saída) | `references/headers-rate-limit-cors.md` |
|
|
28
|
+
| 11 | JWT na URL / token vivo pós-logout | 🟠 Alta | Token no header `Authorization` + revogar no logout | skill `auth-and-secrets` |
|
|
29
|
+
| 12 | Enumeração de usuário (erro revela se e-mail existe) | 🟡 Média | Mensagem genérica + resposta em tempo constante | skill `auth-and-secrets` |
|
|
30
|
+
| 13 | Clickjacking (sem header) | 🟡 Média (1 min) | `X-Frame-Options: DENY` + CSP `frame-ancestors 'none'` | `references/headers-rate-limit-cors.md` |
|
|
31
|
+
|
|
32
|
+
> As quatro primeiras (SQLi, IDOR, mass assignment e RLS permissiva) são **parada de linha**: apareceu, corrige antes de qualquer coisa.
|
|
33
|
+
>
|
|
34
|
+
> Para uma auditoria adversarial completa (caça com prova de exploração + plano priorizado), use a skill `security-audit-pentest`. Esta skill aqui é para **corrigir** uma falha específica da tabela.
|
|
28
35
|
|
|
29
36
|
## References (load on demand)
|
|
30
37
|
|
|
@@ -56,6 +56,17 @@ async headers() {
|
|
|
56
56
|
- Comparações de token/secret: `crypto.timingSafeEqual`, nunca `!==` (detalhe em auth-and-secrets)
|
|
57
57
|
- Sem rate limit = brute force de graça. Somar lockout/CAPTCHA após N falhas no login
|
|
58
58
|
|
|
59
|
+
### Origem do IP atrás de proxy/CDN
|
|
60
|
+
Se o app roda atrás de Vercel/Cloudflare/qualquer proxy, o IP do socket é o do proxy, não o do cliente. Ler o socket direto faz **o mundo inteiro contar como um IP só** e o rate limit deixa de existir na prática.
|
|
61
|
+
- Vercel: use `x-forwarded-for` (ou `req.ip` no runtime que já resolve). Pegue o **primeiro** IP da lista, mas só confie na cadeia que vem do seu proxy.
|
|
62
|
+
- Nunca confie em `x-forwarded-for` cru vindo de origem não-proxy (o cliente falsifica o header). Configure a lib de rate limit para o número certo de proxies à frente.
|
|
63
|
+
|
|
64
|
+
### Custo por chamada (rota que gasta dinheiro real)
|
|
65
|
+
Toda rota que chama modelo de linguagem, dispara SMS, envia e-mail, processa arquivo ou bate em API paga de terceiro precisa de rate limit **e** quota por conta. Rota de agente de IA exposta sem limitador é crítica mesmo sem vazar dado nenhum: 10.000 chamadas em loop viram conta de centenas a milhares de reais/dólares. Estime o custo unitário e multiplique por 10k ao avaliar a rota.
|
|
66
|
+
|
|
67
|
+
### Extração por paginação
|
|
68
|
+
Rota que devolve um registro por vez e, chamada em sequência, entrega a base inteira. Barre com: filtro por dono na query (o mesmo do IDOR), limite máximo de página, e detecção de varredura (muitos ids sequenciais do mesmo cliente).
|
|
69
|
+
|
|
59
70
|
## CORS
|
|
60
71
|
- **Nunca reflita o header `Origin` recebido** de volta em `Access-Control-Allow-Origin` (isso libera qualquer site a chamar sua API com credenciais)
|
|
61
72
|
- Use uma **allowlist explícita** de origens: compare o `Origin` recebido contra a lista e só então ecoe o valor exato daquela origem
|
|
@@ -28,6 +28,38 @@ export async function GET(req: Request, { params }: { params: Promise<{ id: stri
|
|
|
28
28
|
}
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
### RLS: policy permissiva é pior que policy nenhuma
|
|
32
|
+
Ler os arquivos de migration/policy versionados e checar:
|
|
33
|
+
- Toda tabela de domínio tem `ENABLE ROW LEVEL SECURITY`?
|
|
34
|
+
- Nenhuma policy é permissiva: `USING (true)` ou `WITH CHECK (true)` libera geral, mas o painel do Supabase mostra a trava como "ativa". Amarre sempre ao dono: `USING (auth.uid() = user_id)`.
|
|
35
|
+
- Tabela criada em migration recente **sem** policy correspondente = exposta.
|
|
36
|
+
|
|
37
|
+
```sql
|
|
38
|
+
-- ERRADO: mostra RLS ativo no painel, mas libera qualquer um
|
|
39
|
+
create policy "read" on projects for select using (true);
|
|
40
|
+
|
|
41
|
+
-- CERTO: amarra o dono
|
|
42
|
+
alter table projects enable row level security;
|
|
43
|
+
create policy "own rows" on projects
|
|
44
|
+
for select using (auth.uid() = user_id);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
> RLS de verdade é estado do banco, não arquivo. O que está no repo é ponto de partida: confirme o estado real no dashboard/`\d+` do Postgres.
|
|
48
|
+
|
|
49
|
+
## 6. Mass Assignment (atribuição em massa)
|
|
50
|
+
O corpo da requisição inteiro repassado para o banco (`spread` do objeto, `update`/`create` com o payload completo) deixa o atacante setar qualquer coluna, mesmo as que não estão no formulário. Alvos clássicos: `role`, `is_admin`, `plan`, `balance`, `payment_status`, `user_id`/`owner_id`.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
// ERRADO: o cliente manda { name: "x", role: "admin" } e vira admin
|
|
54
|
+
await supabase.from("users").update({ ...body }).eq("id", userId)
|
|
55
|
+
|
|
56
|
+
// CERTO: allowlist explícita, só os campos do formulário
|
|
57
|
+
const { name, bio } = updateSchema.parse(body) // Zod com só os campos permitidos
|
|
58
|
+
await supabase.from("users").update({ name, bio }).eq("id", userId)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Regra: **nunca** `...body` / `...req.body` num write. Sempre desestruture (ou valide com um schema que só contém os campos editáveis). Campos de papel, permissão, plano, saldo, status de pagamento e id de dono nunca vêm do cliente.
|
|
62
|
+
|
|
31
63
|
## 2. Cryptographic Failures
|
|
32
64
|
- HTTPS em tudo, sem exceção
|
|
33
65
|
- HSTS header com includeSubDomains
|
|
@@ -15,6 +15,7 @@ Use esta tabela **só fora de projeto Wizz** (sem `_wizz/`), quando o router map
|
|
|
15
15
|
| Auth, secrets, tokens, OAuth, JWT, Clerk, permissões | `auth-and-secrets` + `web-security` | 1 |
|
|
16
16
|
| Dependências, packages, vulnerabilidades, npm audit | `database-and-deps` | 2 |
|
|
17
17
|
| Segurança, XSS, CSRF, SQLi, IDOR, OWASP, rate limit, CORS, clickjacking, PII na resposta, enumeração de usuário, headers | `web-security` + `auth-and-secrets` | 1 |
|
|
18
|
+
| Auditoria/pentest de segurança do app inteiro, "auditar segurança", "pentest", "encontrar vulnerabilidades", varredura antes de release | `security-audit-pentest` | 1 |
|
|
18
19
|
| Desktop, Electron, contextIsolation, code signing | `desktop-security` | 2 |
|
|
19
20
|
|
|
20
21
|
## Área Técnica — Código e Qualidade
|