docs(audit): análise back-end sênior 2026-05-22 (45 pgs, 50+ achados)#55
Conversation
Auditoria exaustiva (~45 páginas) do back-end Promo Brindes: - 50+ achados classificados por severidade / impacto / prioridade - 3 críticos: ELITE_SIM_KEY hardcoded, RLS permissiva em frontend_telemetry, fallback legacy_no_auth em dispatcher/cron - Inventário real: 81 edge functions, 269 tabelas RLS-100%, 682 migrations, 19 crons (2 órfãos de MV), 112 SECURITY DEFINER (100% com search_path) - Roadmap P0-P3 com esforço estimado - Cross-check com 4 auditorias prévias (resolvido / recorrente / novo) - Anexos com queries SQL read-only de inspeção reaproveitáveis - Validação via MCP Supabase em modo somente leitura https://claude.ai/code/session_011Lgxm1NZGmAztRSvZHX9U3
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughO PR publica documento de auditoria técnica detalhada do backend Supabase, inventariando arquitetura real (tabelas, edge functions, migrations, crons), reportando 3 vulnerabilidades críticas (auth bypass hardcoded, RLS permissivo, fallback legacy), operações (crons órfãos), performance (policies otimizáveis) e maturidade geral com roadmap P0-P3 e critérios bloqueadores para produção. ChangesAuditoria Backend Senior
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related issues
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
Achado SEC-001 da auditoria back-end sênior 2026-05-22 (PR #55): constante "a46c3981-244a-4f81-9f57-bab5c45b5cde" estava hardcoded em _shared/auth.ts e test-contract-orchestrator, aceita como Bearer token e devolvia userRole='dev' + cliente service_role acoplado, criando bypass de autenticação remoto em ≥64 edge functions. Mudanças: - _shared/auth.ts: remove ELITE_SIM_KEY; usa só SIMULATION_BYPASS_KEY do env, com comparação em tempo constante (constantTimeEqual de dispatcher-auth.ts) também para service_role e simulação. - external-db-bridge/index.ts: idem — comparação em tempo constante para service_role e simulação, sem fast-path com === sobre o segredo. - test-contract-orchestrator/index.ts: passa a resolver SIMULATION_BYPASS_KEY via vault/env; devolve 503 se ausente. - scripts/check-no-bypass-literals.mjs: novo guard estático. Falha CI se reaparecer UUID literal em código de auth/bridge ou constante nomeada *BYPASS/*SIM_KEY com valor literal. Roda sem deps. - ci.yml: wire do guard antes de npm ci (fail-fast). Operação pós-merge necessária: - Confirmar SIMULATION_BYPASS_KEY no vault. Se quiser invalidar o valor vazado em código, rotacionar (gerar novo UUID, atualizar vault e integration_credentials). https://claude.ai/code/session_011Lgxm1NZGmAztRSvZHX9U3 Co-authored-by: Claude <noreply@anthropic.com>
Achado SEC-003 da auditoria back-end sênior 2026-05-22 (PR #55): quando WEBHOOK_DISPATCHER_SECRET ou o secret de cron não estavam configurados em vault nem em env, authorizeDispatcher/authorizeCron aceitavam a chamada como "legacy_no_auth" com apenas console.warn. Em PROD os 3 secrets já estão no vault, mas qualquer clone (staging, dev, preview Lovable, fork) herdava acesso anônimo. Mudanças: - _shared/dispatcher-auth.ts: ambos authorizeDispatcher e authorizeCron agora devolvem 503 service_misconfigured (fail-closed) quando o secret não está disponível. Remove o ramo "legacy_no_auth" dos type unions DispatcherAuthMode e CronAuthMode. - _shared/dispatcher-auth.test.ts: corrige tests para usar `await` (authorizeCron é async desde a integração do vault), substitui o teste "legacy_no_auth (retrocompat)" pelo teste "fail-closed 503 (SEC-003)" que valida status code e body. - webhook-dispatcher/index.ts: atualiza comentário de header para refletir o novo comportamento fail-closed. Operação pós-merge necessária: - Confirmar SIM que os 3 secrets continuam no vault de PROD: WEBHOOK_DISPATCHER_SECRET, CRON_SECRET, CONNECTIONS_AUTO_TEST_SECRET. Validado em 2026-05-22 via vault.decrypted_secrets — os 3 estão lá. - Para staging/dev clones: provisionar os mesmos secrets ANTES de invocar webhook-dispatcher ou qualquer cron, senão 503. https://claude.ai/code/session_011Lgxm1NZGmAztRSvZHX9U3 Co-authored-by: Claude <noreply@anthropic.com>
Achado SEC-002 da auditoria back-end sênior 2026-05-22 (PR #55): as policies frontend_telemetry_insert_anon e _insert_authenticated usavam WITH CHECK (true), permitindo qualquer caller inserir registros arbitrários (log poisoning, DoS por inflação, exfiltração via texto livre). Confirmado pelo Supabase advisor `rls_policy_always_true` (lint 0024). Migration drop+recreate ambas as policies com restrições reais: - Anon: força user_id IS NULL (impede impersonação). - Authenticated: força user_id = (select auth.uid()) ou NULL. - Ambas: caps de tamanho em event_type, name, url, user_agent, session_id e metadata::text (≤ 8192 chars). Defesa em profundidade: adiciona CHECK constraint table-level (frontend_telemetry_size_caps_check) para que mesmo se a policy for recriada permissiva no futuro, os caps de tamanho permaneçam ativos. Backwards compat: validado que as 322 linhas atuais (100% anon nos últimos 7 dias) já satisfazem todos os caps (max metadata = 2532 chars, avg 836). telemetryService.ts não precisa mudar — sempre passa user_id implícito NULL. Aplicação: - Via Supabase MCP: apply_migration("20260522010000_harden_frontend_telemetry_rls", ...) - OU via dashboard SQL Editor: cole o conteúdo e Run. - Idempotente (DROP POLICY IF EXISTS + DROP CONSTRAINT IF EXISTS). https://claude.ai/code/session_011Lgxm1NZGmAztRSvZHX9U3 Co-authored-by: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4592d2c09c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| ```ts | ||
| // supabase/functions/_shared/auth.ts:32-39 | ||
| const ELITE_SIM_KEY = "a46c3981-244a-4f81-9f57-bab5c45b5cde"; |
There was a problem hiding this comment.
Redact committed auth-bypass token from the report
This commit republishes the full ELITE_SIM_KEY value in plaintext, which turns a known vulnerability into a broadly reusable secret for anyone with repository read access. If the key is still accepted anywhere (including historical deployments, forks, or lagging environments), an attacker can send it as a Bearer token and gain elevated access; even after code fixes, leaving the literal in git history increases recovery and rotation risk. Replace the literal with a redacted placeholder everywhere in this document and rotate any related bypass secret.
Useful? React with 👍 / 👎.
| | **Performance** | 🟢 adequada | DB médio (~270 MB top tables), 1076 índices, 19 crons coordenados, cache em memória, breaker | | ||
| | **Manutenibilidade** | 🟡 média-alta | Excelente disciplina de engenharia, mas docs defasadas, 88 funções pequenas, `external-db-bridge` >1900 linhas, `expert-chat` >1300 | | ||
| | **Custos** | 🟢 contidos | 13 usuários, 1 organização, base de catálogo de 6k produtos, 81 edge functions invocadas via 19 crons | | ||
| | **Pronto para produção** | 🟢 **GO** após fix de SEC-001 e SEC-002 | Ambos resolvíveis em <1 dia | |
There was a problem hiding this comment.
Require all three blockers before marking production GO
The verdict says production is GO after fixing only SEC-001 and SEC-002, but the same report elsewhere states the system is not ready until SEC-003 is also resolved. This inconsistency can cause teams to stop remediation early and deploy with a documented fail-open auth fallback still present in non-prod/staging clones; align the executive verdict with the stricter three-item gate used later in the report.
Useful? React with 👍 / 👎.
| WHERE c.contype = 'f' | ||
| AND NOT EXISTS ( | ||
| SELECT 1 FROM pg_index i WHERE i.indrelid = c.conrelid | ||
| AND c.conkey[1] = ANY(i.indkey)); |
There was a problem hiding this comment.
Correct FK-index audit SQL to evaluate full key set
The FKs sem índice query only checks c.conkey[1] against pg_index.indkey, so it evaluates just the first FK column and can misclassify composite foreign keys (both false positives and false negatives). Because this SQL is presented as a reusable inspection query, it can drive incorrect index decisions and miss genuine performance issues; it should compare the full FK column list/order to index definitions.
Useful? React with 👍 / 👎.
|
|
||
| ### 7.1 Edge Function invocations | ||
|
|
||
| - **19 crons ativos**, frequência total: ~138 chamadas/hora apenas de cron (`*/5min` × 3 = 36, `*/10min` × 1 = 6, `*/15min` × 2 = 8, hourly × 2 = 2, daily × 11). |
There was a problem hiding this comment.
Fix cron-rate math before using it for cost planning
The hourly estimate is overstated because daily × 11 is treated as 11 calls per hour, but those jobs run 11 times per day (~0.46/hour). With the listed frequencies, the cron total is about 52.5 calls/hour, not 138/hour, so this number can materially skew capacity and cost conclusions in the same section.
Useful? React with 👍 / 👎.
|
|
||
| | # | Função | Proteção interna | Confirmado? | Risco | | ||
| |---|---|---|---|---| | ||
| | 1 | `crm-db-bridge` | Bot-protection + allowlist tabelas + `resolveCredential` | ✅ Sim, similar ao external | 🟡 ver SEC-009 | |
There was a problem hiding this comment.
Resolve contradictory auth status for crm-db-bridge
This row marks crm-db-bridge as auth-confirmed, but later SEC-009 says its auth path was not fully reviewed (lido somente até linha 120) and still needs validation. That contradiction weakens prioritization by simultaneously treating the same endpoint as both verified and unverified; the table and the narrative should agree on the unresolved status.
Useful? React with 👍 / 👎.
…— DOC-001 (#74) Fix do achado DOC-001 da auditoria back-end sênior 2026-05-22. Antes/Depois: | Doc | Valor antigo | Valor real | |---|---|---| | README "Edge Functions" | 47 | 81 | | README "migrations" | 205 | ~710 arquivos / ~685 aplicadas | | README "tabelas com RLS" | 35+ | 269 (100%) | | DEPLOYMENT "drift" | 332 vs 209 / interseção zero | ~710 vs ~685 / drift ~25 | | EDGE_FUNCTIONS header | "50 funções ativas, 2026-04-17" | "81 funções, 24 verify_jwt=false" | | 04_EXPLICACAO_POLICIES | "80+ policies" | "~662 policies em 269 tabelas" | Aponta para o relatório de auditoria como fonte primária do inventário completo (audit/ANALISE_BACKEND_SENIOR_2026-05-22.md, mergeado via #55). https://claude.ai/code/session_011Lgxm1NZGmAztRSvZHX9U3 Co-authored-by: Claude <noreply@anthropic.com>
…C-004 (#72) Achado SEC-004 da auditoria back-end sênior 2026-05-22 (PR #55). Pré-fix: 7 de 8 buckets sem allowed_mime_types, aceitando qualquer MIME; bucket `scripts` sem file_size_limit (sem teto). Adiciona MIME allowlist por bucket conforme uso esperado: - component-media, personalization-images, supplier-logos: imagens - mockup-art-files: imagens + PDF + AI/PSD - product-videos: MP4/WebM/QuickTime/M4V - quarantine: imagens + PDF + texto + octet-stream - scripts: 1MB cap NOVO + text/shell/json/octet-stream Backwards compat: storage.objects hoje só tem 1 row em `scripts` (.sh), os demais buckets estão vazios — sem risco de rejeitar uploads existentes. Aplicado em PROD via apply_migration. https://claude.ai/code/session_011Lgxm1NZGmAztRSvZHX9U3 Co-authored-by: Claude <noreply@anthropic.com>
Achado RLS-002 da auditoria back-end sênior 2026-05-22 (PR #55). Advisor `authenticated_security_definer_function_executable` flaggou 4 funções; análise detalhada determinou ações distintas: Hardening (info disclosure cross-user): - is_admin_or_above(_user_id) → guard: só self ou dev - is_coord_or_above(_user_id) → guard: só self ou dev Documentadas como intencionais (sem ação adicional): - can_access_quote(_quote_id) → avalia auth.uid() interno; safe - org_has_any_members(_org_id) → boolean único; leak material mínimo - check_login_rate_limit(_email, _ip) → anon-callable intencional Migration aplicada em PROD via apply_migration. Mantém SECURITY DEFINER + assinatura idêntica → uso em RLS continua igual. https://claude.ai/code/session_011Lgxm1NZGmAztRSvZHX9U3 Co-authored-by: Claude <noreply@anthropic.com>
Summary
Auditoria back-end sênior exaustiva (~45 páginas, 1150 linhas) do projeto
promo-gifts-v4, gerada via inspeção estática + validação read-only no Supabase de produção (doufsxqlfjyuvxuezpln).Entregue:
audit/ANALISE_BACKEND_SENIOR_2026-05-22.mdVeredito
🟢 GO para produção ampla — após corrigir 3 críticos resolvíveis em ≤1 dia.
Top 3 achados críticos (P0)
ELITE_SIM_KEY = "a46c3981-…"hardcoded em_shared/auth.ts:32etest-contract-orchestrator/index.ts:26— Bearer token bypass total que devolveuserRole='dev'+ cliente service_role em ≥64 funçõesfrontend_telemetry_insert_anoncomWITH CHECK (true)permite anon spammar a tabela com payload arbitrário — log poisoning + DoSlegacy_no_authem_shared/dispatcher-auth.ts:240-253aceita anônimo se secret ausente — em PROD os 3 secrets estão no vault, mas clones/staging herdam fail-openInventário real (vs. docs internos)
publicsearch_pathPontos fortes confirmados
SECURITY DEFINERcomsearch_pathsetado_shared/url-allowlist.ts)Estrutura do relatório
Achados adicionais notáveis
stock_mv_intelligence_refresh,stock_mv_velocity_refresh) referenciam materialized views que não existem mais (SELECT count(*) FROM pg_matviews = 0). Falham silenciosamente todo dia.README,EDGE_FUNCTIONS.md,DEPLOYMENT.md).auth.uid()em policies sem(select ...)— overhead linear no scale.integration_credentials.secret_valueétextplaintext (12 segredos). Confirmado viainformation_schema.columns.console.*no front-end fora dologger.ts; em PROD o logger silenciainfo/warn/debug.Como navegar
caminho:linha+ evidência.Test plan
ELITE_SIM_KEYnão foi commitado em outro repo/fork (git log --all -p -S 'a46c3981')CRON_SECRET,WEBHOOK_DISPATCHER_SECRET,CONNECTIONS_AUTO_TEST_SECRETcontinuam setadosRestrições aplicadas durante a auditoria
execute_sqlSELECT (semapply_migration, semdeploy_edge_function)https://claude.ai/code/session_011Lgxm1NZGmAztRSvZHX9U3
Generated by Claude Code
Summary by cubic
Adds a 45‑page senior back-end audit for
promo-gifts-v4asaudit/ANALISE_BACKEND_SENIOR_2026-05-22.md, with 50+ findings and a GO-to-prod recommendation after three P0 fixes. Includes a real inventory (81 edge functions, 269 tables with 100% RLS, 682 migrations, 19 crons) and a prioritized roadmap.ELITE_SIM_KEYhardcoded bypass; fix permissive INSERT policy onfrontend_telemetry; droplegacy_no_authfallback in dispatcher/crons.SECURITY DEFINERwithsearch_path, vault-protected secrets, strict CORS/HSTS/CSP, anti-SSRF allowlist.Written for commit 4592d2c. Summary will update on new commits. Review in cubic
Summary by CodeRabbit