11. Security
11.1 Webhook Signature Verification
Every inbound webhook POST is authenticated by HMAC-SHA256 over the raw request body, keyed by
WhatsAppCloudApiOptions.AppSecret, compared with CryptographicOperations.FixedTimeEquals (constant-time,
resistant to timing side-channel attacks). This is the only authentication mechanism for the webhook
endpoint, since it is [AllowAnonymous] by necessity — see §8.3.
SignatureValidationEnabled (default true) must never be disabled in production. Disabling it means any
party who discovers the webhook URL can inject arbitrary "inbound messages" and "status updates" into the
Inbox system and the Notification Framework's delivery-receipt pipeline.
11.2 Token Handling
AccessToken(platform) and tenant-scopedWhatsAppOperationalSettings.AccessTokenare long-lived Meta Cloud API tokens — treated as secrets, sourced from environment variables in production (WhatsAppCloudApi__AccessToken), never committed to source control orappsettings.jsondirectly.- Tokens are never included in any API response, log line, or
CommunicationHistory/TenantNotificationLogrecord. - Rotation is supported (
SecretsManifestmarksAccessTokenandVerifyTokenasSupportsRotation: true) — rotating requires updating the environment variable and restarting/reconfiguring the app; there is no hot-reload of these values mid-process beyond the standardIOptionsMonitorbehavior already provided by the configuration system.
11.3 Secret Handling
Five secrets are declared in SecretsManifest (see §4.2):
VerifyToken, AppSecret, AccessToken, PhoneNumberId, BusinessAccountId. All are
ProductionRequired: true — SecretsHealthCheck flags a missing value as a startup warning in Production.
None of these values, nor the tenant-scoped equivalents in WhatsAppOperationalSettings, are ever logged,
including in LogRawPayload debug mode (which logs the payload, not the configured secrets used to
validate it).
11.4 Permission Gates
Every endpoint except the two webhook actions requires both authentication ([Authorize], implied by
[MustHavePermission]) and a specific permission — see the full per-endpoint table in
§6 API Reference. Two permission families exist:
PermissionConstants.WhatsApp.* (manual test endpoints only) and PermissionConstants.WhatsAppInbox.*
(the Inbox system). A tenant admin should scope agent roles to only the Inbox permissions their support team
actually needs — WhatsAppInbox.ViewAll in particular grants visibility into every agent's conversations,
not just the caller's own.
11.5 Diagnostic Endpoint Risks
CommunicationDiagnosticsController (see §6.9)
exposes detailed configuration and resolution-decision information, and one endpoint
(SmokeTest/WhatsApp) sends a real WhatsApp message to whatever toPhone is supplied. Treat this
controller as admin/support-tier only:
GET HealthandGET Diagnostics/*reveal whether credentials are configured (not their values), template resolution decisions, and configuration warnings — useful to an attacker for reconnaissance if exposed too broadly.POST SmokeTest/WhatsAppperforms a real Meta API call and a real template dispatch — restrict theCommunications.SmokeTestpermission tightly, and never point it at a production customer's phone number during testing.- None of these endpoints require anything beyond the platform's standard
[MustHavePermission]gate — there is no additional rate-limiting or IP-allowlisting layer specific to diagnostics. If broader exposure is needed (e.g. a support portal), add that control at the gateway/reverse-proxy layer, not by weakening these permissions.
11.6 Production Safety Notes
LogRawPayloadmust stayfalsein production — raw webhook JSON can contain customer message content.SignatureValidationEnabledmust staytruein production.- The Meta CDN media URL is never exposed to a frontend client (see §10.6) — always proxy media downloads through the backend.
- Test/diagnostic endpoints that perform real Meta API calls (
WhatsAppController's four test endpoints,CommunicationController.Test/WhatsApp,CommunicationDiagnosticsController.SmokeTest/WhatsApp) should be restricted to admin/support roles and never wired into any customer-facing UI flow.
