Uma integração de newsletter pode parecer apenas um formulário com um campo de e-mail. Por trás dele, porém, pode haver um endpoint próprio que usa uma credencial do servidor para cadastrar contatos em Mailchimp ou em outro provedor. O risco aparece quando o backend deixa o visitante escolher parâmetros que deveriam vir da configuração confiável do formulário.
1. O básico: navegador, servidor e provedor
O frontend é a página aberta no navegador. Ele mostra os campos e monta a requisição. O backend é a API ou função do site que recebe essa requisição. O provedor é o serviço externo que mantém a lista de contatos.
Quando o backend conversa com o provedor usando uma chave de API guardada no servidor, ele possui uma capacidade que o visitante não deveria controlar diretamente. O backend precisa decidir qual formulário está sendo enviado, a qual audiência ele pertence e quais regras de inscrição se aplicam.
Uma audiência é a lista ou grupo de contatos de destino. O double opt-in é um fluxo em que a pessoa recebe uma mensagem e precisa confirmar a inscrição. Consentimento, audiência e confirmação são decisões diferentes: a presença de um e-mail válido não prova, por si só, que seu titular pediu a inscrição.
2. O modelo de dados
No black box, trate cada valor enviado pelo navegador como entrada controlada pelo cliente.
Um campo oculto continua editável; JavaScript também pode ser pausado ou modificado. Entre
os valores comuns estão email, form_id, audience_id,
tags e double_opt_in.
O dado de origem, ou source, é o valor que entra na aplicação. O sink é o ponto onde ele causa um efeito sensível, como uma chamada à API do provedor que cria ou atualiza um contato. Seguir esse caminho ajuda a separar uma mudança visual no navegador de uma mudança realmente aceita pelo servidor.
3. A teoria da falha: confiança indevida em parâmetros
Imagine que o backend recebe audience_id e double_opt_in do
cliente. Se usa esses valores sem compará-los com uma configuração autorizada, o visitante
pode tentar trocar a lista de destino ou alterar o fluxo de confirmação.
O problema não é o cliente conseguir editar a própria requisição — isso é esperado. O problema é o servidor tratar os valores alterados como decisões confiáveis. Uma validação de formato pode confirmar que um ID parece válido, mas não responde se aquele formulário tem permissão para usar essa audiência.
Também é importante separar autorização de proteção contra CSRF. Um token público ou nonce pode ajudar a reconhecer uma requisição originada pelo fluxo do site, mas não deve conceder ao visitante o direito de escolher a audiência nem de mudar a política de inscrição.
4. Onde procurar essa funcionalidade
Procure funções de cadastro em newsletter, assinatura de mailing list, captura de leads, inscrição em novidades ou formulários que sincronizam contatos com um CRM. A aplicação pode usar uma API em Node, PHP, Python, uma função serverless ou uma plataforma de automação.
Na aba Network do navegador, observe para onde o formulário envia os dados. Se a requisição vai para uma rota do próprio domínio, existe um backend a investigar. Se o formulário envia diretamente ao provedor, essa falha específica no backend do site pode não existir; ainda assim, não conclua nada apenas pela aparência do formulário.
5. Validação black box, passo a passo
Passo 1 — confirme o escopo e o ambiente. Use um ativo autorizado. Prefira staging, uma conta de teste ou um mock do provedor. Uma requisição válida pode alterar contatos reais.
Passo 2 — capture o fluxo normal. Envie um endereço controlado por você e guarde a rota, o método, os nomes dos parâmetros e a resposta. Redija tokens e dados pessoais ao salvar evidências.
Passo 3 — formule uma hipótese. Pergunte se o servidor decide a audiência a partir do ID do formulário ou se aceita uma audiência enviada pelo cliente. Faça uma alteração por vez.
Passo 4 — teste com dados próprios. Em staging, altere ou remova o identificador do formulário e, quando autorizado, envie a audiência de teste. Para consentimento, use apenas um contato controlado e uma configuração isolada.
Passo 5 — confirme no sink. Confira os logs do backend ou o estado do contato na audiência de teste. Uma resposta HTTP 200 não prova que o provedor aceitou a mudança, e uma mensagem de sucesso na interface não prova qual estado foi gravado.
Passo 6 — pare após a confirmação. Não use endereços de terceiros, não enumere IDs de audiências e não faça carga ou repetição em massa. Um único teste controlado costuma bastar para demonstrar o controle indevido.
6. PoC conceitual para laboratório
O formato real depende da requisição observada. Este exemplo representa um backend próprio e serve somente para um ambiente de teste. Não o envie a um domínio público sem autorização e sem entender o efeito da integração.
POST /api/subscribe
Content-Type: application/json
{
"email": "ENDERECO_CONTROLADO_PELO_PESQUISADOR",
"form_id": "formulario-de-teste",
"audience_id": "audiencia-de-teste",
"double_opt_in": false
}
O achado é confirmado se o backend usar sua credencial e realizar a inscrição com a
audiência ou regra controlada pelo pedido, sem verificar se esses valores pertencem à
configuração permitida para formulario-de-teste. Se o backend ignorar o campo,
rejeitar a requisição ou resolver a configuração no servidor, essa hipótese não se confirma
por esse teste.
7. Do intermediário ao avançado
Limite de confiança e invariantes
Escreva o que precisa permanecer verdadeiro: cada formulário usa uma audiência previamente definida; somente o servidor decide se a confirmação é necessária; o e-mail recebido não pode alterar esses controles. Depois, verifique se cada endpoint mantém essas invariantes, inclusive quando faltam campos ou quando um identificador é inválido.
Autorização por objeto e separação entre clientes
Em sistemas com várias marcas, clientes ou contas, um form_id pode selecionar
configurações de outra organização. Verifique se o servidor associa o formulário ao tenant
correto, em vez de aceitar um identificador de audiência arbitrário. Não tente acessar
dados de outros clientes: valide apenas com recursos de teste autorizados.
Estado e transições
Modele estados como pending, subscribed e
unsubscribed. A análise avançada pergunta quais transições o endpoint permite,
quem pode solicitá-las e se uma atualização pode reativar um contato sem o fluxo esperado.
A resposta do provedor e suas regras também fazem parte da validação.
Replay, abuso e integrações
Depois de validar a autorização, examine separadamente repetição de pedidos, limites de frequência, tratamento de falhas, duplicatas e webhooks de confirmação. Um limite por cliente pode reduzir abuso, mas não corrige a autorização incorreta sobre audiência ou consentimento. Não faça testes de volume sem autorização explícita.
Credenciais e fronteiras do provedor
Confirme que a chave de API não aparece no HTML, no bundle JavaScript ou na resposta ao navegador. Uma chave exposta é um achado diferente. Quando o backend mantém a chave, a evidência importante para este caso é mostrar que valores do cliente controlam uma chamada autenticada do servidor.
8. Falsos positivos comuns
Um campo editável não basta para provar impacto. O backend pode ignorá-lo; o provedor pode rejeitar a operação; ou o formulário pode enviar diretamente ao serviço sem um proxy do site. Uma lista visível no navegador também não prova que o usuário consegue gravar contatos nela. Confirme o efeito no sistema de destino de teste.
9. Impacto e severidade
Se confirmado, o impacto pode incluir inscrições indesejadas, alteração de contatos ou uso indevido da audiência configurada. O alcance depende das credenciais e permissões do backend, das audiências disponíveis e das regras do provedor. Não alegue acesso à chave, leitura de contatos ou comprometimento da conta se o teste não demonstrar isso.
Para um relatório de bounty, descreva as pré-condições, o parâmetro controlado, o estado observado no destino de teste e os limites da evidência. A classificação final deve seguir o impacto real e as regras do programa.
10. Como corrigir
Associe cada formulário a uma configuração fixa no servidor. Receba do cliente apenas um identificador opaco do formulário e os dados necessários do contato; resolva audiência, tags e política de confirmação no backend. Rejeite formulários desconhecidos, aplique autorização por tenant e mantenha a credencial do provedor fora do frontend.
A regra prática é simples: o navegador pode enviar uma intenção de inscrição; o servidor decide a operação permitida.
← voltar