Skip to content

Fail-closed webhook authentication

ADR-003: Fail-closed webhook authentication

Section titled “ADR-003: Fail-closed webhook authentication”

Status: Accepted Date: 2026-04-14 Deciders: Mishaal Murawala (enforced during security audit)

The Cal.com webhook handler at /webhooks/calcom receives booking lifecycle events (created, rescheduled, cancelled) and triggers Slack notifications. The initial implementation accepted unauthenticated requests if CALCOM_WEBHOOK_SECRET was not configured — a fail-open design.

A security audit identified this as CRITICAL: any attacker reaching the endpoint could forge booking events, triggering fake Slack notifications and potentially poisoning scheduling state.

We will fail closed — if CALCOM_WEBHOOK_SECRET is not set, the webhook handler returns HTTP 500 with CONFIG_MISSING error. Additionally, HMAC verification uses crypto.subtle.verify() for timing-safe comparison instead of string equality.

  • No unauthenticated webhook processing is possible, even during initial setup
  • Timing-safe HMAC comparison prevents side-channel attacks
  • Explicit error message tells the operator exactly what’s missing
  • Cal.com webhooks won’t work until the secret is configured — requires manual setup step during onboarding
  • Adds a dependency on CALCOM_WEBHOOK_SECRET wrangler secret for any tenant using Cal.com
  • If the secret is rotated in Cal.com but not in the Worker, all webhooks will be rejected until the Worker secret is updated. Mitigated by the explicit error logging.

Fail-open with logging (accept but log warning)

Section titled “Fail-open with logging (accept but log warning)”
  • Rejected because: “log and accept” means the system is vulnerable until someone reads the logs. Security boundaries must be enforced, not observed.
  • Rejected because: Cal.com’s outbound IPs are not guaranteed stable, and IP-based auth is weaker than cryptographic verification.