Securing Webhook Endpoints: How We Validate Twilio Callbacks in Human and Veterinary Telemedicine

A webhook endpoint that accepts unauthenticated POST requests is an open door. In a telemedicine platform where Twilio webhook events trigger recording logic and billing — and where GDPR and telemedicine compliance obligations apply — that door needs a lock.

The Attack Surface Nobody Talks About

Twilio drives the room lifecycle in our video consultation platform, used for both human and veterinary telemedicine under PawSquad and VetCloud. For every significant room event — participant-connected, participant-disconnected, room-ended, recording-completed, composition-available — Twilio fires a signed HTTP POST to a configured StatusCallback URL. Your server receives it and acts on it.

The problem is straightforward: there is nothing in a raw HTTP POST that proves it came from Twilio. Any caller with your callback URL can inject fabricated events. A spoofed room-ended event could stop a recording prematurely, corrupt consultation metadata, or trigger billing logic against a session that never actually closed. A replay attack — resending a legitimate past event — can produce the same outcome without fabricating anything. These are not theoretical edge cases in a platform that processes real clinical data.

Telemedicine platforms operate under GDPR and HIPAA-adjacent obligations. Session recordings, participant identities, and consultation timing metadata are regulated data. Treating the StatusCallback endpoint as a trusted internal surface — without signature validation — is an architectural mistake that regulators and auditors will eventually surface.

How Twilio Signs Requests and How We Validate Them

Twilio's signing mechanism is HMAC-SHA1. For every StatusCallback POST, Twilio computes a signature over the full request URL concatenated with the POST body parameters sorted alphabetically by key, using your account AuthToken as the HMAC secret. That signature is attached to the request in the X-Twilio-Signature header.

On the receiving end, we use the request validation utility from the official Twilio C# SDK, passing the reconstructed request URL, the raw POST parameters, and the incoming signature value. The result is a boolean. Every webhook handler runs this check as the first operation — before deserializing the payload, before touching any business logic. If the signature does not match, the endpoint returns 403 Forbidden immediately and nothing downstream executes.

C# — Signature validation with proxy-aware URL reconstruction
// ── Step 1: Reconstruct the exact URL Twilio signed ──────────────────────────────
// Twilio signs the full URL it POSTed to. Behind a reverse proxy or load balancer,
// Request.Scheme will be "http" even if Twilio used "https".
// A scheme mismatch here produces a silent 403 — no error, just a failed HMAC.
var scheme = Request.Headers["X-Forwarded-Proto"].FirstOrDefault()
             ?? Request.Scheme;                           // fallback for local dev

var requestUrl = $"{scheme}://{Request.Host}{Request.Path}{Request.QueryString}";

// ── Step 2: Validate signature — always the first call, before any payload access ──
// Twilio computes HMAC-SHA1 over: requestUrl + POST params sorted alphabetically.
// The SDK handles parameter sorting internally — pass form values as-is.
var isValid = twilioValidator.Validate(
    requestUrl,                               // must be byte-for-byte what Twilio used
    Request.Form.ToDictionary(...),           // SDK sorts alphabetically before hashing
    Request.Headers["X-Twilio-Signature"]    // HMAC-SHA1 sent by Twilio on every POST
);

// ── Step 3: Reject immediately — nothing downstream executes ──────────────────────
if (!isValid)
    return StatusCode(403);

// Signature verified — safe to process the event, update room state, push via SignalR

The implementation is intentionally simple. The security guarantee comes from the AuthToken secret, not from complexity. What makes this non-trivial is not the validation call itself — it is everything around it: URL reconstruction, proxy headers, parameter ordering. That is where validation silently breaks in most production deployments.

Three Pitfalls That Will Break Validation Silently

The most common failure mode is URL mismatch. Twilio computes the HMAC over the exact URL it posted to. If your server reconstructs a different URL, the signatures will not match even though the request is legitimate. This happens in three concrete ways.

First, reverse proxies that rewrite paths or strip non-standard ports. If Twilio calls https://api.example.com:8443/webhook and your application sees https://api.example.com/webhook, validation fails. Second, load balancers that terminate TLS and forward traffic as plain HTTP. Your application reconstructs an HTTP URL, but Twilio signed an HTTPS URL. The fix is to read the X-Forwarded-Proto header and use it during URL reconstruction. Third, alphabetical sorting of POST parameters — Twilio sorts before computing the HMAC, and your validator must present them in the same order. The Twilio SDK handles this if you pass parameters as a dictionary, but pre-processing the form body before validation can introduce ordering bugs.

All three of these fail silently in production. You get a 403 and no clear indication that infrastructure, not application logic, is the source.

Defense in Depth Beyond Webhook Validation

Webhook signature validation is one layer. The platform runs two more independently.

All non-webhook API endpoints require a scoped API key, enforced at the middleware level. Keys are bound to a specific tenant identifier, so a key issued to one integration cannot reach another tenant's data. This layer is entirely independent of Twilio's signing mechanism and covers the full API surface outside the StatusCallback path.

The third layer addresses a subtler vector: Twilio participant identity strings. When a client joins a Programmable Video room, the JWT access token it presents carries an identity claim that flows through Twilio's infrastructure and surfaces in every subsequent webhook event for that room. We validate those identities at the point of token issuance — enforcing format constraints and rejecting reserved or potentially privileged values before the token is ever signed. If a malformed identity somehow reaches a webhook payload, it is blocked before it can affect session records or trigger downstream logic. Three independent layers — if any one is bypassed, the others still hold.

What This Architecture Actually Buys You

HMAC-SHA1 is not a strong algorithm by 2026 cryptographic standards. It is Twilio's design choice, not ours, and there is no alternative signing mechanism available for Programmable Video webhooks. The mitigation is operational: rotate the AuthToken on a defined schedule, treat it as a high-value secret, monitor and alert on failed validation attempts — but never log the raw X-Twilio-Signature header value, as that exposes the basis for offline attack attempts.

Webhook idempotency is a related concern that often gets overlooked. Twilio may redeliver a StatusCallback if the first delivery times out or receives a non-2xx response. Handlers that are not idempotent — that process a room-ended event twice and bill twice, or start two composition jobs — introduce real data integrity risk. Idempotency keys on event processing are not optional in production.

Strict URL matching also creates friction in local development. A tunnel tool like Ngrok is required to receive real Twilio StatusCallbacks locally, and the tunnel URL must be registered in the Twilio console for the test account. That overhead is real. It is also an acceptable price for a validation model that holds in production for platforms handling regulated clinical consultation data.

At Smartnet, this security pattern is part of how we build telemedicine infrastructure from the start — not retrofitted after an incident. The implementation is not complicated. Getting the infrastructure details right — reverse proxies, TLS termination, URL reconstruction, parameter ordering — is where the actual work lives.

The service this webhook layer protects runs against multiple database engines. Read how we handle runtime database provider switching in EF Core 10.

Building a platform that handles sensitive consultation data?

Smartnet designs and implements secure video and telemedicine infrastructure, including webhook validation, identity management, and GDPR-aware architecture.

Contact us →