Skip to content

Security

How Emithook keeps inbound events authentic, outbound deliveries safe, and payloads private.

Inbound authenticity

Every inbound endpoint's signature is verified using the provider preset: Shopify, Stripe (300 s tolerance), Slack (v0=, 5-min replay window), Meta, Razorpay, or generic HMAC. Per the founding invariant (ADR-0021), the immortal edge accepts and durably buffers every request in <100 ms and never drops an accepted event — it does not verify or 401 on the accept path. Verification runs in the processing plane as a verdict: a verified event is routed and delivered; a bad signature is quarantined — durable and inspectable, but never delivered; an unknown endpoint is dropped (with a metric); an inactive/paused endpoint is parked (durable, replayable). Unauthenticated events are therefore still never delivered — the guarantee is unchanged; only where verification happens moved (off the accept path, so a flood of bad signatures can never threaten ingest availability). Optional per-endpoint IP allowlists and edge WAF/rate-limiting add defense in depth.

For inbound email, the analogue is SPF / DKIM / DMARC verification, recorded on each event with a configurable drop/quarantine policy.

Outbound signing

Outbound webhooks are signed with the Standard Webhooks spec, verbatim:

  • Headers webhook-id, webhook-timestamp (Unix seconds), webhook-signature.
  • Signed content is exactly {id}.{timestamp}.{body} (the raw bytes sent), HMAC-SHA256 → base64 → v1,<sig>.
  • Per-destination secret whsec_…. Rotation signs with current + previous keys (space-delimited) for a 24 h overlap, so in-flight messages keep verifying.

Receivers verify with any off-the-shelf library — against the raw request body (the #1 cause of verification failures).

SSRF protection — the highest-severity outbound control

Because customers (and, in the Send platform, their end-customers) supply arbitrary destination URLs, the delivery path is a Server-Side Request Forgery surface — the class behind the Capital One breach via the cloud metadata endpoint. Emithook applies these controls at delivery time, not just at registration:

  • HTTPS and standard ports only; reject encoded-IP literals and @ userinfo.
  • Resolve DNS through a public resolver, validate the resolved IP against the reserved/private denylist (169.254.169.254, 127.0.0.0/8, 10/8, 172.16/12, 192.168/16, 169.254/16, fc00::/7), then connect to that pinned IP — defeating DNS-rebinding (TOCTOU).
  • Never follow redirects (3xx = failure).
  • Strip internal headers/credentials.
  • Route all delivery egress through a Smokescreen-style proxy in an isolated subnet with a default-deny network policy that cannot reach internal services.

Defense in depth = an app-layer IP check and network-layer egress isolation. This is a launch gate, not a hardening nice-to-have.

Data residency & retention

Payloads at rest stay in your selected region — the managed cloud is multi-region by design (ADR-0020), with India (ap-south-1) available today and more regions coming — excepting transient edge buffering during a regional failover (documented in the DPA). Encrypted at rest (SSE/KMS). Retention is a per-domain control (7/30/90 d, or "metadata only" to null payloads for sensitive endpoints); the hourly archive has its own longer lifecycle (default 13 months) then hard delete.

Access control

Scoped API keys (read ⊂ write ⊂ admin) gate every API/CLI/MCP call. Per-org RBAC (Admin/Developer/Viewer), optional 2FA/MFA and SSO/SAML, an active-sessions view with per-session revoke, and an audit log of console actions. Least-privilege IAM per service; secrets in a secrets manager, never inline.

Next

Apache-2.0 licensed · a Finnoto product