Checklist e referência de segurança. Revise antes de todo PR.
Antes de abrir ou mergear qualquer PR, verifique:
- Nenhuma chamada direta à API Anthropic — usa sempre
callAI()via proxy -
Authorization: Bearer <token>presente em toda chamada ao proxy -
user_id: session?.user?.idem todo INSERT e UPSERT no Supabase - Nenhum
error.messagedo Supabase exposto na UI — só log no console
- Todo
<a href={url}>valida protocolo:if (/^https?:\/\//i.test(url)) - Nenhum dado de usuário renderizado como
dangerouslySetInnerHTML - Inputs de texto não executam código (sem
eval, semFunction())
- Nenhum secret com prefixo
VITE_— valores com esse prefixo são embutidos no bundle público -
ANTHROPIC_API_KEYvive apenas como secret da Edge Function no Supabase -
AI_PROXY_URLsem fallback hardcoded — falha explicitamente se não configurado
- Nova tabela tem as 4 políticas RLS (
auth.uid() = user_idem SELECT/INSERT/UPDATE/DELETE) - Foreign keys com tipos compatíveis (
process_idétext, nãouuid) - Migrations aplicadas via
apply_migration, não direto no SQL editor
- Fluxo de recovery usa
clearRecovery()só após senha salva com sucesso -
session === undefinedexibe spinner (carregando), não tela de login - Modo demo não acessa banco — guards
if (isDemo)em todo CRUD
| Vetor | Mitigação |
|---|---|
| Chave Anthropic exposta | Edge Function com verify_jwt: true — chave nunca sai do servidor |
| Acesso a dados de outro usuário | RLS por auth.uid() = user_id em todas as tabelas |
| XSS via conteúdo do recrutador | React escapa HTML por padrão — sem dangerouslySetInnerHTML |
Open redirect via jobUrl |
Validação https?:// antes de renderizar <a> |
| Abuso do proxy de IA | Rate limit 20 req/min por usuário (in-memory na Edge Function) |
| CSRF | Supabase Auth usa tokens Bearer — não usa cookies de sessão |
| Clickjacking | X-Frame-Options: DENY em vercel.json |
| MIME sniffing | X-Content-Type-Options: nosniff em vercel.json |
| Referrer leak | Referrer-Policy: strict-origin-when-cross-origin em vercel.json |
ALTER TABLE nome_tabela ENABLE ROW LEVEL SECURITY;
CREATE POLICY "users_select_own" ON nome_tabela
FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "users_insert_own" ON nome_tabela
FOR INSERT WITH CHECK (auth.uid() = user_id);
CREATE POLICY "users_update_own" ON nome_tabela
FOR UPDATE USING (auth.uid() = user_id);
CREATE POLICY "users_delete_own" ON nome_tabela
FOR DELETE USING (auth.uid() = user_id);supabase/functions/anthropic-proxy/index.ts — verify_jwt: true
Rejeita: requests sem JWT, tokens expirados, >20 req/min por usuário.
Secrets obrigatórios:
ANTHROPIC_API_KEYALLOWED_ORIGIN— domínio Vercel de produção
| Item | Onde | Prioridade |
|---|---|---|
Configurar ALLOWED_ORIGIN na Edge Function |
Supabase → Edge Functions → Secrets | 🔴 Alta |
| Aumentar senha mínima para 12 chars | Supabase → Auth → Password settings | 🔴 Alta |
| Rate limiting persistente (Supabase KV) | Edge Function | 🟡 Média |
- Nunca chamar
https://api.anthropic.comdiretamente — sempre via proxy - Nunca expor
error.messagena UI — log no console, mensagem genérica ao usuário - Nunca renderizar
<a href={var}>sem validarhttps?:// - Nunca INSERT/UPSERT sem
user_id: session?.user?.id - Nunca criar tabela sem RLS — aplicar as 4 políticas na mesma migration
- Nunca prefixar secrets com
VITE_