@audit segurança — Fluxo de Security Scan + Triagem
Extensão obrigatória do
@audit segurança. SSOT do fluxo de Lovable Security Scan → triagem contra codebase → plano priorizado → execução.Última atualização: 2026-05-07 · v1.0
Este doc é para auditoria automatizada de segurança (executa scan, analisa findings, gera plano). Para investigar uma vulnerabilidade já conhecida, use o checklist genérico em AUDIT.md Parte C (§11). Para o protocolo de migração de DB, use MIGRATION_SAFETY_PROTOCOL.
1. Quando invocar
Dispara o fluxo deste doc quando:
- Usuário escreve
@audit segurançaou pede explicitamente para "rodar scan", "analisar findings", "verificar segurança". - Pré-release de feature que toca auth, RLS, webhook, edge function pública.
- Painel de Security mostra findings novos (ou após uma rodada de fixes, para validar).
- Mudança em policy RLS, claims de JWT, política de webhook ou storage bucket.
Se o pedido é "corrigir um finding específico que eu já vi", não rode scan novo — vá direto para a etapa E3 (triagem) com o finding já em mãos.
2. Ferramentas disponíveis ao agente
| Ferramenta | Uso |
|---|---|
security--run_security_scan | Dispara um novo scan (5 scanners). Leva ~1–2 min. |
security--get_scan_results | Lê findings atuais. force=true se um scan estiver rodando. |
security--get_table_schema | Schema do banco + prompt de análise (útil para correlacionar RLS). |
supabase--linter | Lints programáticos do Postgres/Supabase (RLS desabilitada, search_path, etc.). |
secrets--fetch_secrets | Confirmar se um secret apontado como ausente existe de fato. |
security--manage_security_finding | mark_as_fixed / ignore / update_details. Sempre com justificativa. |
security--update_memory | Atualizar a memória de segurança (o que é público intencional, riscos aceitos). |
Os 5 scanners atuais:
supabase_lov— análise de RLS pelo agente Lovable (mais inteligente que o linter).agent_security— análise de código (logs, fail-open, randomness, hardcoded secrets).supabase— linter programático (search_path, security definer exposto, RLS habilitada sem policy).connector_scan— integrações/conectores expostos.dependency_audit—bun audit(cobertura também via.github/workflows/audit.yml).
3. Fluxo passo a passo (5 etapas)
E1. Disparo
1. security--run_security_scan
2. Aguardar (poll com get_scan_results force=true) até "scanning" virar "completed".
3. Se findings > 20 → avisar usuário que vou quebrar a triagem em 2 turnos.E2. Inventário
Para cada finding, registrar em tabela mental:
| Campo | Origem |
|---|---|
scanner_name | supabase_lov / agent_security / supabase / connector_scan / dependency_audit |
internal_id | Único — usado para mark_as_fixed / ignore |
level | error / warn / info |
arquivo:linha apontado | extraído de details |
E3. Triagem contra codebase
Para cada finding, executar:
- Ler o arquivo apontado (não a linha isolada — pelo menos ±30 linhas para entender contexto).
- Cruzar com regras do projeto:
- Memórias
mem://security/*(em especialfail-close-architectural-principle,rls-design-and-syntax-standards,payment-integration-security-standards,mural-otp-timing-safe-verification-standard). - ADRs em
docs/architecture/adrs/. - SSOTs em
docs/security/(RLS_DESIGN_GUIDE, AUTHENTICATION, RLS_POLICIES).
- Memórias
- Classificar em uma de 4 categorias:
| Categoria | Critério | Ação |
|---|---|---|
| CRÍTICO real (P0) | Vulnerabilidade explorável agora; nada mitiga upstream. Ex: privilege escalation em RLS, fail-open em webhook de pagamento sem outra validação. | Plano imediato + 3-fases se for migration. |
| WARN real (P1/P2) | Vulnerabilidade explorável mas com mitigação parcial (rate limit, log de auditoria, defesa em profundidade). Ex: Math.random em OTP com lockout progressivo. | Plano numa próxima janela; documentar mitigação no doc. |
| Falso positivo | O guard existe mas o scanner não enxerga. Ex: bypass via X-Gateway que na verdade é checado pelo Worker upstream antes de chegar; SECURITY DEFINER com guard interno (auth.jwt()->>'sub'). | manage_security_finding(operation: ignore, reason: ...) + update_memory com a regra para não reincidir. |
| Risco aceito | Comportamento intencional documentado. Ex: bucket público porque serve avatares; RPC get_public_platform_config retorna apenas chaves whitelisted. | ignore + memória What to not create vulnerabilities for. |
Checklist de perguntas-pivô (rodar para cada finding antes de classificar)
- [ ] Há guard upstream (Cloudflare Worker, edge function de auth) que o scanner não vê?
- [ ] O secret apontado como ausente está de fato configurado? (cruzar com
secrets--fetch_secrets) - [ ] A policy "permissiva" tem
WITH CHECKou guard via funçãoSECURITY DEFINERinterna? - [ ] O log apontado vaza dado real ou só metadado/comprimento (
length=N)? - [ ] O endpoint "aberto" exige cookie HttpOnly/JWT validado depois (no body do handler) que o scanner não percebeu?
- [ ] A tabela "sem SELECT policy" é propositalmente deny-all (ex:
senha_historico)? - [ ] A função
SECURITY DEFINER"executável por anon/authenticated" tem guard de portal/role no corpo (RAISE EXCEPTIONse não for o caller esperado)?
E4. Plano priorizado
Output canônico para o usuário, antes de tocar em código:
## Sumário
- N findings analisados (X CRÍTICO, Y WARN, Z falsos positivos, W risco aceito)
- M scans / arquivos tocados
## Plano
| # | Finding | Categoria | Impacto | Correção | Esforço | Prioridade |
|---|---|---|---|---|---|---|
| 1 | privilege_escalation_usuario_papeis | CRÍTICO | School manager grants admin role | WITH CHECK papel_id IN (...) | Médio (migration 3-fases) | P0 |
| ... |
## Falsos positivos a marcar como ignorar
- `xgateway_burst_bypass`: motivo curto. Memória a atualizar: ...
## Aprovação
Quais itens você quer que eu execute agora? (P0 sempre recomendado)Não execute nenhum fix antes da resposta do usuário.
E5. Execução (após aprovação)
Para cada item aprovado:
- Migrations RLS →
MIGRATION_SAFETY_PROTOCOL(Fase 1 textual → Fase 2 SQL+checklist → Fase 3 execução). - Edge Functions → fail-close obrigatório, sanitização de logs (memory
backend-error-sanitization),try/catchexplícito (memorysupabase-error-handling-pattern). - Após validar fix com novo scan →
manage_security_finding(operation: mark_as_fixed, explanation: ...). - Se virou regra durável → criar memória em
mem://security/*e atualizarmem://index.md. - Documentar mudança no doc de SSOT correspondente (RLS_POLICIES, AUTHENTICATION, etc.) — sem doc atualizado, a entrega está incompleta (regra
DOCUMENTATION_MAINTENANCE).
4. Padrões de remediação recorrentes (atalhos)
| Sintoma do scanner | SSOT da correção |
|---|---|
RLS faltando escopo escola_id ou WITH CHECK | RLS_DESIGN_GUIDE §WITH CHECK + cast ::text/::uuid |
| Webhook fail-open quando secret ausente | Memory payment-integration-security-standards — fail-close: if (!secret) return false |
| PII em log (CPF / telefone / JID) | Mask helper já existente em supabase/functions/_shared/wasender-whatsapp.ts (telefone.slice(0,6) + '****') |
Math.random() em OTP | crypto.getRandomValues(new Uint32Array(1)) — extrair generateSecureOTP() em _shared/otp-utils.ts |
Privilege escalation em usuario_papeis | Enum de papéis permitidos no WITH CHECK: papel_id IN (SELECT id FROM papeis WHERE nome IN ('coordenador', 'diretor', 'pedagogico', 'professor', 'marketing')) |
Portal lendo sem filtro escola_id | Adicionar AND (escola_id)::text = (auth.jwt()->>'escola_id') |
Função SECURITY DEFINER exposta a anon/authenticated | Avaliar: (a) REVOKE EXECUTE FROM anon, authenticated se for interna, (b) manter exposta mas com guard RAISE EXCEPTION no corpo se for RPC pública. |
senha_historico sem SELECT policy | Adicionar policy explícita deny-all documentada (USING (false)) para deixar intent claro. |
| Cookie/JWT logado em texto puro | Substituir por presença + comprimento: 'Cookie: [present, length=' + h.length + ']' |
5. Limites e quebra em múltiplos turnos
Quebrar em mais de 1 turno quando:
- >15 findings densos — gera contexto demais.
- Mudanças que tocam >3 RLS — cada migração precisa de seu próprio 3-fases.
- Qualquer item que dependa de validação de RPC + edge function + frontend — 1 finding = 1 PR.
dependency_auditsugere bump de major — sair do@audit segurançae abrir tarefa de upgrade independente.
6. Anti-padrões (não fazer)
- ❌ Aplicar fix antes de apresentar plano e receber aprovação.
- ❌
mark_as_fixedantes de rodar novo scan que confirme remoção. - ❌
ignoresemupdate_memorycorrespondente — o scanner reincide. - ❌ Mexer em RLS sem 3-fases (regra crítica do projeto).
- ❌ Tratar
dependency_auditcomo bloqueante para release de feature — é contínuo (workflowaudit.ymlsemanal). - ❌ Reescrever política RLS sem ler
RLS_DESIGN_GUIDEantes. - ❌ Marcar finding como falso positivo sem ler ±30 linhas do arquivo apontado.
7. Output esperado (template)
Quando reportar ao usuário:
- Sumário executivo (3 linhas: total / CRÍTICOs / falsos positivos).
- Tabela do plano (formato §E4).
- Falsos positivos marcados com motivo e link para memória atualizada.
- Pergunta final: "Aprova execução de quais itens?".
Não despejar todo o JSON do scan no chat — sintetize.
Referências
- AUDIT.md — Checklist geral
- RLS_DESIGN_GUIDE
- AUTHENTICATION
- MIGRATION_SAFETY_PROTOCOL
- DOCUMENTATION_MAINTENANCE
- Memória:
mem://security/audit-security-scan-flow