Pular para o conteúdo

11. Riscos e dívida técnica

Levantamento feito em outubro de 2026 por inspeção de código e navegação com conta de teste. Nenhum teste de intrusão foi executado contra produção. Os IDs são estáveis: um risco novo recebe o próximo número livre e entra na seção correspondente, mesmo fora de ordem.

Sev. Escala
Crítico Explorável hoje, com impacto financeiro ou de dados
Alto Explorável com algum conhecimento, ou quebra um processo
Médio Dívida que aumenta o custo de mudança ou o risco operacional
Baixo Higiene

Crítico Webhook de pagamento sem verificação de autenticidade

apps/web/src/app/api/webhook/route.ts aceita qualquer POST, separa order_nsu em orderId-cartId e marca o pedido como PAID usando um token de serviço. Não há verificação de assinatura, de origem, nem consulta ao gateway, e paid_amount não é comparado com o total. O próprio cliente conhece o orderId (está na URL de confirmação), então é possível marcar um pedido como pago sem pagar, e isso dispara produção e e-mail.

Agravante: o token de serviço (PAYMENT_BYPASS_TOKEN) é aceito pelo middleware do Fastify como sessão válida em qualquer rota, inclusive as de admin, porque o return acontece antes da checagem de papel.

Ação: ao receber o webhook, consultar o pagamento na InfinitePay (transaction_nsu/invoice_slug) antes de aceitar; validar paid_amount ≥ totalAmount; tornar a operação idempotente; registrar o receipt_url.

Alto Rotas de escrita do catálogo só com requireAuth

Criar, editar e excluir peças, coberturas (e nomes, tipos, características, reforços e configurações de logo), características e tamanhos de produto, slide show, a criação de produtos (POST /products) e os uploads de imagens de catálogo (/upload/products, /pieces, /coverages, /banners, /docs, /coverage-logos) exigem apenas usuário logado, não administrador. Qualquer profissional cadastrado consegue alterar o catálogo pela API.

Ação: trocar por requireAdmin() em todas as rotas POST/PUT/PATCH/DELETE de catálogo e cobrir com teste de autorização por rota.

Alto Rotas sem autenticação

  • DELETE /health/cache/flush limpa todo o Redis sem autenticação. O comentário no código diz “Admin only”, mas não há preHandler.
  • O CRUD de help-info (itens de suporte) não tem nenhum preHandler.

Ação: proteger com requireAdmin(); considerar expor /health/* detalhado só na rede interna.

Alto Página de pagamento Pix com código fictício

/home/payment/[orderId] monta uma string Pix “de exemplo” (comentário no próprio código), sem CRC, com recebedor MOLDAPE / SAO PAULO fixo. O fluxo real usa a InfinitePay, mas a rota continua acessível.

Ação: remover a rota ou redirecioná-la para o checkout real.

Alto Tokens de sessão gravados em log do servidor

O middleware presentation/middleware/auth.ts faz console.log de todos os cookies com seus valores a cada requisição autenticada. Quem tiver acesso aos logs do Coolify consegue sequestrar sessões, inclusive de administradores.

Ação: remover o log de valores (manter, no máximo, os nomes dos cookies em nível debug) e rotacionar as sessões depois do deploy da correção.

Crítico Credenciais de produção no histórico do git

Até a versão 2.1.0, o .env.example da raiz, o docker-compose.yml, o fallback do AUTH_SECRET no web, um documento em docs/ e a pasta .idea/ guardavam valores reais: senha e IP do PostgreSQL, senha do Redis, senha de app do SMTP, AUTH_SECRET/JWT_SECRET e o PAYMENT_BYPASS_TOKEN. Desde a 2.2.0 os arquivos versionados só têm valores dev-only-…, mas os valores antigos continuam acessíveis no histórico para quem tem acesso ao repositório.

Ação: rotacionar todas essas credenciais no Coolify, no banco, no Redis e no Gmail; avaliar a reescrita do histórico (git filter-repo) e restringir o acesso de leitura ao repositório.

Baixo Dados pessoais em console.log no código do web

O checkout faz console.log do payload de pagamento (nome, endereço, valor) e a página de pagamento faz console.log(order). Em produção o build já remove console.log (compiler.removeConsole no next.config.ts, mantendo só error e warn), então os dados não chegam ao navegador do cliente; o risco fica restrito a ambientes de desenvolvimento e homologação.

Ação: tirar os logs do código (ver MF-22).

Alto CI quebrado: pnpm run healthcheck não existe e não há Dockerfile na raiz. O pipeline não protege a main. Ver Implantação.

Médio Migrations sem passo de release definido

O build do web não roda mais prisma migrate dev, e desde a 2.2.0 existe pnpm prisma:migrate:deploy (prisma migrate deploy, que só aplica as migrations já versionadas). Falta executá-lo de forma automática: hoje as migrations de produção dependem de alguém rodar o comando na mão.

Ação: configurar pnpm prisma:migrate:deploy como pre-deploy command do order-lifecycle no Coolify (dono do schema), com backup antes.

Médio Sem máquina de estados no pedido (RN-12): qualquer transição é permitida.

Médio Volume único de arquivos sem backup documentado: plantigrafias e PDFs de produção estão só no volume uploads da VPS.

Ação: backup diário do volume (Coolify tem backups agendados para bancos; para volume, usar restic ou rclone para um storage externo) e teste de restauração.

Baixo Código legado convivendo com o atual: na versão 2.1.0 saíram o TanStack Router, o @uploadcare/upload-client, o workflow Azure/AKS, o Material Tailwind, o axios, o Jest e 58 arquivos sem uso no web. Restam a nomenclatura “uploadcare” em componentes que hoje usam o upload próprio e a documentação antiga que descreve um apps/auth e Django. Ver Limpeza técnica e o Changelog.

Médio Verificar posse do recurso (IDOR): rotas como GET /carts/user/:userId, GET /orders/:id, PUT /drafts/:id e DELETE /upload/plantigraphy/:filename exigem login. Falta confirmar, nos casos de uso, que o recurso pertence ao usuário da sessão.

Ação: teste automatizado por rota com dois usuários (A não pode ler nem alterar o que é de B).

Baixo get-session duplicado: cada navegação chama /api/auth/get-session duas vezes.

Desenvolvido e documentado por
Nós Tecnologia · Desenvolvimento Criativo