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 |
Segurança
Seção intitulada “Segurança”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/flushlimpa 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 nenhumpreHandler.
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).
Operação e processo
Seção intitulada “Operação e processo”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 porNós Tecnologia · Desenvolvimento Criativo

