Skip to content

[Segurança] Formulário Enterprise injeta HTML não escapado no e-mail enviado a equipe #1122

Description

@elio-neto

Problema

O endpoint público POST /api/enterprise interpola cinco campos controlados pelo remetente direto no
corpo HTML de um e-mail enviado para contact@anoma.ly, sem nenhum escape. AWS.sendEmail usa a mesma
string simultaneamente como corpo Text e como corpo Html, portanto o cliente de e-mail do
destinatário interpreta a marcação.

Por que é explorável

O endpoint não tem autenticação — apenas um honeypot de campo alias (linhas 65-69) e um regex de
formato de e-mail (75-78). Não há rate limit nem limite de tamanho por campo. Os campos message,
name, role, company e phone entram na string sem tratamento, e a string já contém tags <br>,
isto é, é tratada como HTML por construção.

O projeto tem DOMPurify 3.3.1 como dependência e o aplica corretamente na renderização de markdown
(packages/ui/src/components/markdown.tsx:45-48), mas não há nenhuma função de escape no caminho do
e-mail.

Evidência

packages/console/app/src/routes/api/enterprise.ts:80-86:

const emailContent = `
${body.message}<br><br>
--<br>
${body.name}<br>
${body.role}<br>
${body.company ? `${body.company}<br>` : ""}${body.email}<br>
${body.phone ? `${body.phone}<br>` : ""}`.trim()

Linhas 100-105 — o envio, com Reply-To também controlado pelo remetente:

AWS.sendEmail({
  to: "contact@anoma.ly",
  subject: `Enterprise Inquiry from ${body.name}`,
  body: emailContent,
  replyTo: body.email,
})

packages/console/core/src/aws.ts:46-55 — a mesma string vai como Text e como Html:

Body: {
  Text: {
    Charset: "UTF-8",
    Data: input.body,
  },
  Html: {
    Charset: "UTF-8",
    Data: input.body,      // <-- mesma string, interpretada como HTML
  },
},

Impacto

Injeção de HTML em caixa de entrada interna. Permite:

  • montar mensagens que se passam por comunicação legítima do próprio sistema
  • inserir links de phishing com texto de âncora enganoso (<a href="https://atacante">clique aqui para aprovar</a>)
  • esconder o conteúdo real com marcação e inserir imagens de rastreamento
  • falsificar o bloco de assinatura inteiro, inclusive o e-mail de contato, que também é interpolado

Como Reply-To é definido com body.email, a resposta da equipe vai para o endereço escolhido pelo
atacante. A execução de script não é o vetor principal (clientes de e-mail bloqueiam); a fraude visual é.

Sugestão de correção

  1. Escapar cada campo de usuário antes de interpolar no HTML.
  2. Melhor: separar os dois corpos. Mudar a assinatura de AWS.sendEmail para receber text e html
    distintos, montar o text com os valores crus e o html com os valores escapados.
  3. Adicionar limite de tamanho por campo.
  4. Adicionar rate limit por IP no endpoint, que hoje não tem nenhum.

Critérios de aceite

  • Todo campo de usuário é escapado antes de entrar no HTML do e-mail
  • AWS.sendEmail recebe corpos Text e Html separados e não reaproveita a mesma string
  • Existe limite de tamanho por campo no POST /api/enterprise
  • Existe rate limit por IP no POST /api/enterprise
  • Teste: submissão contendo <a href> e <img> chega ao destinatário como texto literal
  • Auditoria dos e-mails já recebidos por esse formulário, procurando marcação injetada

Labels sugeridas: security, alta

Achado da auditoria estatica de seguranca do commit 0465a5d. Relatorio completo em docs/security-audit/relatorio-auditoria-seguranca.pdf.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions