Skip to content

ADR-0006 — Accepting ManyChat's unsigned webhooks ​

Status: superseded by ADR-0012 · Date: 2026-09-14

Context ​

ManyChat does not sign Dynamic Block requests. There is no HMAC, no timestamp, and no nonce — only headers we configure, sent verbatim on every request. We cannot verify that a request genuinely originated from ManyChat, only that the sender knows a secret.

Decision ​

Accept the risk, with compensating controls:

  • Shared secret compared using crypto.timingSafeEqual, never ===.
  • TLS required; it is the only protection against interception and replay.
  • Two secrets valid during rotation, so rotation needs no flow downtime.
  • Rate limiting per IP and per subscriber, bounding a leaked secret's blast radius.
  • The endpoint exposes no data: it accepts a message and returns a reply. There is nothing to read back, so a valid-looking forged request can waste model budget but cannot exfiltrate conversation history.
  • Budget caps mean the worst case of a leaked secret is bounded spend, not an unbounded bill.

Consequences ​

  • Residual risk: anyone holding the secret can invoke the agent. Detection is via rate-limit and budget alerting rather than via request authentication.
  • If ManyChat adds request signing, revisit immediately — this ADR is the record of why the weaker control exists.
  • An IP allowlist was considered and rejected: ManyChat publishes no stable egress range, so it would break silently.