Malvo-Signature. Verifique o HMAC do corpo HTTP cru
antes de aplicar qualquer efeito. Headers customizados e o IP de egress estático continuam
válidos como defesa em profundidade.
Aplicações criadas após este lançamento já nascem com um signing secret. Aplicações existentes
têm um prazo de adequação publicado no Dashboard (90 dias). A Malvo não interrompe entregas
depois do prazo — o modelo antigo (só headers + IP) deixa de ser suficiente.
HMAC (Malvo-Signature)
Formato:
{t}.{raw body}, hex minúsculo, com o signing secret da
aplicação (whsec_…). Durante uma rotação o header pode trazer dois v1. Use os bytes
exatos do POST — nunca JSON.parse + JSON.stringify.
Vetor de teste:
GET /webhooks.
Durante uma rotação o SDK aceita os dois secrets:
t fresco, então
retries de até ~3 h continuam válidos. Deduplique por eventId — o HMAC não substitui isso.
Quem não usa o SDK: HMAC-SHA256 de "{t}." + raw_body com a string inteira do secret
(incluindo whsec_), compare em tempo constante, aceite qualquer v1 do header.
Headers customizados por webhook
Cada webhook pode carregar um mapa deheaders (nome → valor) que é enviado verbatim em toda
entrega. É aí que você coloca o seu segredo compartilhado.
headers:
- Na API pública, o mapa é aceito em
POST /webhooksePATCH /webhooks/{id}e não volta em nenhumGET/list. - No Dashboard, owners e admins veem e editam os headers do endpoint. O signing secret HMAC é outro material — mora na aplicação e só aparece ao revelar na página Webhooks.
- Não coloque o signing secret HMAC nesse mapa: a Malvo já envia
Malvo-Signature.
Rotação dos headers customizados via PATCH
Pela API pública a rotação do mapa é umPATCH que reescreve os headers:
A resposta pública do
PATCH confirma a atualização mas não ecoa os headers. No Dashboard
você edita o mapa na ficha do endpoint. A rotação do signing secret HMAC é o botão
Rotacionar da página Webhooks (o previous vale 24 h).Rotação do signing secret
- No Dashboard → Webhooks, Rotacionar gera um secret novo e mantém o anterior por 24 h.
- No receiver, passe os dois para
verifyWebhookSignatureenquanto migra. - Encerrar anterior invalida o secret antigo na hora. Uma segunda rotação com previous
ainda válido retorna
409.
IP allowlisting
Todas as entregas saem de um único IP de egress estático. Liberar esse IP no firewall/WAF é defesa extra, não substitui o HMAC.Checklist de validação do receiver
Valide toda requisição recebida nesta ordem, antes de aplicar qualquer efeito:1
HMAC
Malvo-Signature confere com o signing secret da aplicação sobre o corpo cru.2
IP de origem
O IP de origem é o egress estático da Malvo (valor vigente via suporte, até o Dashboard
publicar).
3
Header de autenticação
O header de auth customizado bate com o segredo configurado, se você usa um.
4
Corpo e evento
O corpo é JSON válido e
event é um valor que você assina.5
Idempotência
O
eventId ainda não foi processado (deduplique — veja Entrega & Retry).t do HMAC expira em 5 minutos; cada retry da Malvo traz um t novo.
Persista o eventId e trate duplicatas como no-op. Não rejeite o evento pela idade do outbox.
Handler de exemplo
O padrão é: HMAC → parse → idempotência → 200 → processar async. Useexpress.raw (ou o
equivalente no seu framework). express.json() consome o body e o HMAC quebra.
401 na assinatura faz a Malvo reentregar (útil se o relógio do receiver atrasou). Secret errado
ou express.json() no lugar de .raw() também geram 9 retries — corrija o receiver, não o
cadastro do webhook.
Troubleshooting de entrega
Próximos passos
Entrega & Retry
O schedule de retry, idempotência e a reconciliação noturna.
Referência — Webhooks
POST, GET, PATCH e DELETE de webhooks, incluindo o campo headers.