🔒 AUDITORIA DE SEGURANÇA COMPLETA — rv-adv
🔒 AUDITORIA DE SEGURANÇA COMPLETA — rv-adv
Data: 18/04/2026 | Auditor: Automated Security Review Versão do Código: current | Severidade: Ver tabela abaixo
1.1 AUTENTICAÇÃO E AUTORIZAÇÃO
FINDING 1.1.1 [CRÍTICA]
Severidade: 🔴 CRÍTICA
Localização: supabase/functions/_shared/auth.ts:136-137
CWE: CWE-345 (Insufficient Verification of Data Authenticity)
Descrição: Tokens HS256 são decodificados SEM verificação de assinatura.
Evidência:
// Linha 136-137
if (alg === "HS256") {
const payload = decodePayloadUnsafe(token); // ⚠️ Sem verificação de assinatura!
if (!payload) return null;
O código apenas decodifica o payload Base64 sem verificar a assinatura HMAC-SHA256. Qualquer atacante que consiga forjar um JWT com role="service_role" ou role="authenticated" e exp adequadamente terá acesso total.
Recomendação:
- Usar
jose.jwtVerify()com o JWT_SECRET para tokens HS256 - Alternativamente, rejeitar tokens HS256 e forçar migração para ES256
- Documentar claramente o risco se HS256 for aceito sem verificação
Status: ⚠️ REQUER CORREÇÃO IMEDIATA
FINDING 1.1.2 [CRÍTICA]
Severidade: 🔴 CRÍTICA
Localização: supabase/functions/delete-google-calendar/index.ts:1-63
CWE: CWE-306 (Missing Authentication for Critical Function)
Descrição: Edge Function SEM qualquer autenticação. Qualquer usuário pode deletar eventos do Google Calendar.
Evidência:
// Não há authenticateRequest, nenhuma verificação de JWT
serve(async (req) => {
if (req.method === "OPTIONS") {
return new Response("ok", { headers: corsHeaders });
}
try {
const { event_id } = await req.json();
// ⚠️ Qualquer pessoa pode deletar QUALQUER event_id!
Recomendação:
- Adicionar
authenticateRequestno início da função - Validar que o user_id do token corresponde ao proprietário do evento
- Ou implementar HMAC signature validation para webhooks
Status: ⚠️ REQUER CORREÇÃO IMEDIATA
FINDING 1.1.3 [CRÍTICA]
Severidade: 🔴 CRÍTICA
Localização: supabase/functions/sync-google-calendar/index.ts:1-143
CWE: CWE-306 (Missing Authentication for Critical Function)
Descrição: Edge Function SEM autenticação. Qualquer pessoa pode sincronizar eventos.
Evidência:
// Sem verificação de autenticação
serve(async (req) => {
if (req.method === "OPTIONS") {
return new Response("ok", { headers: getCorsHeaders(req.headers.get("origin")) });
}
// ⚠️ Qualquer pessoa pode criar/atualizar eventos no Google Calendar!
const { pericia_id } = await req.json();
Recomendação:
- Adicionar
authenticateRequestno início da função - Validar que o user_id do token tem permissão para modificar a perícia
Status: ⚠️ REQUER CORREÇÃO IMEDIATA
FINDING 1.1.4 [ALTA]
Severidade: 🟠 ALTA
Localização: supabase/functions/scrape-tnu/index.ts:319-326
CWE: CWE-287 (Improper Authentication)
Descrição: Autenticação fraca - apenas verifica presença do header Authorization, não valida o JWT.
Evidência:
const authHeader = req.headers.get("authorization") ?? "";
const jwt = authHeader.replace(/^Bearer\s+/i, "");
if (!jwt) {
return new Response(JSON.stringify({ error: "Unauthorized" }), {
status: 401,
// ⚠️ Apenas verifica se existe Bearer token, NÃO valida o token!
Recomendação:
- Usar
authenticateRequestdo módulo_shared/auth.ts - OU implementar verificação completa do JWT
Status: ⚠️ REQUER CORREÇÃO
FINDING 1.1.5 [MÉDIA]
Severidade: 🟡 MÉDIA
Localização: supabase/functions/import-tramita-clients/index.ts:267
CWE: CWE-295 (Improper Certificate Validation)
Descrição: Bug de copiar/colar - usa SERVICE_ROLE_KEY onde deveria usar ANON_KEY.
Evidência:
// Linha 267
const supabaseAnonKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? ""; // ⚠️ ERRADO!
// Deveria ser:
const supabaseAnonKey = Deno.env.get("SUPABASE_ANON_KEY") ?? "";
Isto expõe o service_role key ao código cliente, comprometendo RLS.
Recomendação:
- Corrigir para
Deno.env.get("SUPABASE_ANON_KEY") - Testar autenticação JWT após correção
Status: ⚠️ REQUER CORREÇÃO
FINDING 1.1.6 [MÉDIA]
Severidade: 🟡 MÉDIA
Localização: supabase/functions/_shared/rate-limit.ts
CWE: CWE-837 (Insufficient Rate Limit)
Descrição: Rate limiting em memória é ineficaz em Edge Functions serverless.
Evidência:
// Cada isolate tem seu próprio Map - rate limits não são compartilhados
const rateLimits = new Map<string, { count: number; expiresAt: number }>();
Em ambiente Deno Deploy/Edge, cada requisição pode executar em isolate diferente, invalidando o rate limiting.
Recomendação:
- Usar Redis ou similar para rate limiting distribuído
- Ou usar o endpoint
/auth/v1/admin/userspara tracking
Status: ℹ️ MELHORIA RECOMENDADA
1.2 VALIDAÇÃO DE ENTRADA
FINDING 1.2.1 [ALTA]
Severidade: 🟠 ALTA
Localização: supabase/functions/ti-webhook-receiver/index.ts:255-262
CWE: CWE-20 (Improper Input Validation)
Descrição: Event type não é validado contra lista de valores esperados.
Evidência:
// Linha 255-262
if (event_type !== "publications.created") {
console.log(`[Webhook TI] Evento ignorado: '${event_type}'`);
return new Response(
JSON.stringify({ message: "Evento ignorado", event_type }),
// ⚠️ Informa ao atacante quais tipos de eventos existem
);
}
Recomendação:
- Usar validação com conjunto fechado (enum)
- Não informar detalhes sobre eventos existentes na resposta
Status: ℹ️ MELHORIA RECOMENDADA
FINDING 1.2.2 [BAIXA]
Severidade: 🔵 BAIXA
Localização: supabase/functions/ti-webhook-receiver/index.ts:170-176
CWE: CWE-347 (Improper Verification of Cryptographic Signature)
Descrição: Mesmo secret usado para HMAC-SHA256 e Bearer token.
Evidência:
// Linha 170-176
const queryToken = url.searchParams.get("token");
if (queryToken) {
if (timingSafeEqual(queryToken, secret)) {
return { ok: true, method: "query-token" };
}
}
// ⚠️ O mesmo secret valida HMAC e Bearer
Recomendação:
- Usar secrets diferentes para cada método de autenticação
- Preferir HMAC-SHA256 como único método
Status: ℹ️ MELHORIA RECOMENDADA
FINDING 1.2.3 [INFO]
Severidade: 🟢 INFO
Localização: src/components/ui/chart.jsx:62-79
CWE: N/A
Descrição: Uso de dangerouslySetInnerHTML para CSS dinâmico.
Evidência:
// Linhas 62-79
return (
<style
dangerouslySetInnerHTML={{
__html: Object.entries(THEMES)
.map(/* ... */)
.join("\n"),
}}
/>
);
Avaliação: SEGURO - conteúdo é gerado programmaticamente, não inclui input do usuário.
FINDING 1.2.4 [INFO]
Severidade: 🟢 INFO Localização: Múltiplas Edge Functions CWE: N/A
Descrição: Boas práticas observadas - validação de entrada robusta.
Evidência:
chat-jurisprudencia/index.ts:397-413- Validação estrita de tipos com verificações explícitasgenerate-embedding/index.ts:91-122- Limites de tamanho e validação de taskTypeai-proxy/index.ts:517-528- Verificação de campos obrigatóriosdatajud-bypass/index.ts:77-94- Validação de campos obrigatórios e tipos
Recomendação: Manter este padrão.
1.3 GERENCIAMENTO DE SEGREDOS
FINDING 1.3.1 [INFO]
Severidade: 🟢 INFO Localização: Variáveis de ambiente CWE: N/A
Descrição: Segredos armazenados em variáveis de ambiente (Vault do Supabase).
Evidência:
const GEMINI_API_KEY = Deno.env.get("GEMINI_API_KEY");
const DATAJUD_API_KEY = Deno.env.get("DATAJUD_API_KEY");
const supabaseServiceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "";
Avaliação: CORRETO - Supabase Edge Functions usam Vault para secrets.
Recomendação:
- Garantir que todas as API keys estejam no Vault
- Nunca commitar .env files
- Rotacionar secrets periodicamente
RESUMO EXECUTIVO
| Severidade | Qtd | Findings |
|---|---|---|
| 🔴 CRÍTICA | 4 | Auth bypass (delete-calendar, sync-calendar), JWT sem verificação |
| 🟠 ALTA | 2 | Auth fraca (scrape-tnu), validação entrada insuficiente |
| 🟡 MÉDIA | 2 | Bug de copia/cola, rate limiting ineficaz |
| 🔵 BAIXA | 1 | Shared secrets |
| 🟢 INFO | 3 | Boas práticas, CSS safe |
AÇÕES PRIORITÁRIAS
- [IMEDIATO] Corrigir
delete-google-calendaresync-google-calendar- adicionar autenticação - [IMEDIATO] Corrigir
_shared/auth.ts- verificar assinatura HS256 - [URGENTE] Corrigir
import-tramita-clientslinha 267 - usar ANON_KEY correto - [URGENTE] Corrigir
scrape-tnu- usar autenticação completa
BOAS PRÁTICAS IDENTIFICADAS
✅ CORS restrito a domínios específicos em todas as Edge Functions
✅ Headers de segurança (X-Content-Type-Options, X-Frame-Options, HSTS)
✅ Autenticação via authenticateRequest implementada corretamente
✅ Rate limiting implementado (com ressalvas)
✅ Validação de entrada rigorosa na maioria das funções
✅ HMAC-SHA256 para webhooks
✅ Timeout em chamadas externas
Documento gerado automaticamente em 2026-04-18