fix(security): fecha IDOR de QR/instance do WhatsApp e remove 4 funções mortas - #125
Conversation
…es mortas
Aplicado direto em produção (tnnnlkbymytvtqngbbqh) e registrado no ledger
via supabase_migrations.schema_migrations, seguindo o protocolo de
supabase_apply_migration bugado descrito no CLAUDE.md.
M2 (IDOR, auditoria 28/08/2026): get_connection_qr_code e
get_connection_instance são SECURITY DEFINER, EXECUTE concedido a
'authenticated', sem checagem de posse/role. A tabela
whatsapp_connections já restringe SELECT a admin/supervisor via RLS,
mas SECURITY DEFINER ignora RLS — qualquer agente logado podia chamar
supabase.rpc('get_connection_qr_code', {...}) e ler o QR code de
pareamento (risco de sequestro de sessão WhatsApp) ou o instance_id.
Zero chamadas no front hoje (grep confirma); fechado por defesa em
profundidade com o mesmo guard já usado na policy da tabela
(is_admin_or_supervisor(auth.uid())). Testado ao vivo por simulação
com request.jwt.claims: agent → NULL, admin → valor real.
B1/B6: remove 4 funções mortas reativáveis apontadas na mesma
auditoria — prevent_role_escalation e mask_channel_credentials
(0 triggers as referenciam), get_reset_requests_safe (referencia a
coluna inexistente password_reset_requests.reset_token, 42703 se
chamada) e get_own_reset_requests (resto do subsistema de reset
customizado já dropado em 20260827170000). Zero dependentes
confirmados via pg_depend antes do DROP.
schema-catalog.json/schema-manifest.json/types.ts não foram tocados
neste PR — o workflow types-sync detecta o drift no push para main e
abre o PR de sincronização automaticamente (mesmo padrão de todo PR
anterior de migration neste repo).
Validado: check-migration-drift.mjs (offline OK, ledger não
comparado sem DESTINO_URL), supabase-usage-guard (0 violações novas),
118/118 testes de scripts/db-audit/*.test.mjs.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018N9zUcTpab3dWsuR3ZSSBj
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
adm01-debug has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
|
Warning Review limit reachedNext included review available in 7 minutes. View limit detailsLimit details: You’ve used the included review currently available. Your 99 included PR review attempts over the past 7 days set your current allowance at 1 review per hour. Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (1)
Comment |
There was a problem hiding this comment.
🟡 Changes recommended
Do jeito que está (DDL já aplicado no DB vivo, mas sem atualizar types.ts/schema-catalog/schema-manifest), o DB Live Guard em push para main tende a falhar por drift até a sincronização ser mergeada.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Este PR endurece o acesso a dados sensíveis de conexões WhatsApp no banco (Supabase) corrigindo um vetor de IDOR em RPCs SECURITY DEFINER e removendo funções órfãs/reativáveis que não têm dependentes ativos.
Changes:
- Adiciona checagem
is_admin_or_supervisor(auth.uid())dentro deget_connection_qr_code(uuid)eget_connection_instance(uuid)para impedir leitura por usuários autenticados sem privilégio. - Remove 4 funções mortas (
prevent_role_escalation,mask_channel_credentials,get_reset_requests_safe,get_own_reset_requests) viaDROP FUNCTION IF EXISTS.
File summaries
| File | Description |
|---|---|
| supabase/migrations/20260901210000_fix_connection_idor_and_drop_dead_secdef.sql | Corrige IDOR em RPCs de WhatsApp e remove funções SQL órfãs/arriscadas. |
Review details
- Files reviewed: 1/1 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
1 issue found across 1 file
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="supabase/migrations/20260901210000_fix_connection_idor_and_drop_dead_secdef.sql">
<violation number="1" location="supabase/migrations/20260901210000_fix_connection_idor_and_drop_dead_secdef.sql:14">
P3: Both RPCs are recreated as SECURITY DEFINER with EXECUTE still granted to authenticated, even though the PR confirms zero front-end callers. The `is_admin_or_supervisor(auth.uid())` gate is correct, but keeping a SECURITY DEFINER function callable by every authenticated user preserves the attack surface this PR set out to close — any future regression in the gate (or a new caller) silently reopens the IDOR. Since there are zero callers, the strongest remediation is to drop these functions too (same pattern as the 4 dead functions in this migration) or at minimum `REVOKE EXECUTE ... FROM authenticated, public`, re-creating them only when a real caller exists.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
adm01-debug has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
There was a problem hiding this comment.
adm01-debug has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
M2 — IDOR (auditoria 28/08/2026)
get_connection_qr_code(uuid)eget_connection_instance(uuid)sãoSECURITY DEFINER,EXECUTEconcedido aauthenticated, sem checagem de posse/role. A tabelawhatsapp_connectionsjá restringeSELECTa admin/supervisor via RLS (Admin supervisor view connections=is_admin_or_supervisor(auth.uid())), masSECURITY DEFINERignora RLS — qualquer agente logado podia chamarsupabase.rpc('get_connection_qr_code', {...})e ler o QR code de pareamento do WhatsApp (risco de sequestro de sessão) ou oinstance_id, sem passar pela policy.Zero chamadas a essas RPCs no front hoje (
grepconfirma) — fechado por defesa em profundidade, com o mesmo guard já usado na policy da própria tabela.Testado ao vivo por simulação (
request.jwt.claims, sem mutação persistida):B1/B6 — 4 funções mortas reativáveis
prevent_role_escalation— a barreira real de escalação de privilégio hoje éaudit_role_changes+ guard direto emprofiles/user_roles(migrations20260830010000/20260830030000). 0 triggers referenciam esta função. Religá-la reabriria o bug A-01 (reversão silenciosa de escalação documentado na auditoria de 27/08).mask_channel_credentials— stub de trigger ("credentials masking é feito via view segura"), 0 triggers a referenciam.get_reset_requests_safe— referencia a coluna inexistentepassword_reset_requests.reset_token(42703se chamada). Resto do subsistema de reset customizado já foi dropado na migration20260827170000.get_own_reset_requests— mesma família morta, zero chamadas no front.Zero dependentes confirmados via
pg_dependantes doDROP FUNCTION.Aplicação
DDL aplicada direto em produção (
tnnnlkbymytvtqngbbqh) e registrada emsupabase_migrations.schema_migrations(protocolo do CLAUDE.md —supabase_apply_migrationbugado neste ambiente). Ostatementsdo ledger é byte-idêntico ao arquivo desta migration, então o DB Live Guard deve validar por conteúdo canônico direto, sem precisar de exceção emmigration-evidence.json.schema-catalog.json/schema-manifest.json/types.tsnão foram tocados aqui — seguindo o padrão já estabelecido neste repo, o workflowtypes-syncdetecta o drift no push paramaine abre o PR de sincronização automaticamente.Validação
node scripts/db-audit/check-migration-drift.mjs→ offline OK (327 arquivos válidos; comparação com o ledger vivo roda no DB Live Guard pós-merge).node scripts/db-audit/supabase-usage-guard.mjs→ 0 violações novas.node --test scripts/db-audit/*.test.mjs→ 118/118 passam.🤖 Generated with Claude Code
https://claude.ai/code/session_018N9zUcTpab3dWsuR3ZSSBj
Summary by cubic
Fixes an IDOR in the WhatsApp connection RPCs where any authenticated agent could read pairing QR codes or instance IDs, and drops four dead functions that could re-open known security bugs.
Bug Fixes
get_connection_qr_codeandget_connection_instancenow return NULL unless the caller is admin or supervisor; previouslySECURITY DEFINERbypassed RLS.prevent_role_escalation,mask_channel_credentials,get_reset_requests_safe, andget_own_reset_requests— none have live triggers, callers, or dependent objects.prevent_role_escalationwould reintroduce the A-01 silent privilege escalation bug.Migration
supabase_migrations.schema_migrations.types-syncwill open the schema sync PR on merge.Written for commit c0dfe8b. Summary will update on new commits.