Microsoft Teams Notificationsfor WHMCS · Documentation
v1.3.0

Security & Permissions

The webhook URL is the only secret. The module validates it before every request, pins TLS, refuses redirects and redacts it from every log entry.


Microsoft Teams Notifications does not create database tables, does not register a bot and does not request Microsoft Graph permissions. Delivery uses a single HTTPS POST to the URL generated by Teams. That makes the URL the entire security boundary: anyone who holds it can post to the channel, and anyone who can read it in a log has the same power.

Webhook URL validation

Every request — including the connection test — validates the URL before cURL is called. The provider webhook and any per-rule Webhook Override go through the same checks:

  • HTTPS only. Plain HTTP is rejected.
  • No credentials. A URL containing user:pass@ is rejected.
  • No fragment. A URL containing # is rejected.
  • Length and shape. The URL must parse and be 2,048 characters or fewer.
  • Host allowlist. Teams connector hosts and Power Automate Workflows hosts are accepted. Anything else requires Allow Custom Host.
  • Path shape. A legacy URL must contain /webhook/ or /webhookb2/ and /IncomingWebhook/. A Workflows URL must contain /workflows/, /triggers/ and /paths/invoke.
  • Signature rules. A legacy URL must not carry a query string. A Workflows URL must carry its signature query string.
  • Port. Only 443 is accepted unless a custom host is allowed.

The optional Card Icon URL is validated separately: it must be a valid HTTPS URL of 512 characters or fewer. Teams fetches the image from the client, so the URL must be publicly reachable; the module does not proxy or cache it.

Host patternPurpose
outlook.office.com, outlook.office365.comLegacy Office 365 Incoming Webhook.
*.webhook.office.com, *.webhook.office365.comLegacy tenant-scoped connectors.
*.logic.azure.comPower Automate Workflows trigger.
*.api.powerplatform.comPower Platform Workflows trigger.
Any HTTPS hostOnly when Allow Custom Host is ticked, for national clouds or a trusted proxy.

Transport hardening

cURL optionValueWhy
CURLOPT_FOLLOWLOCATIONfalseA redirect cannot send the token or signature to another host.
CURLOPT_SSL_VERIFYPEERtrueThe server certificate must chain to a trusted CA.
CURLOPT_SSL_VERIFYHOST2The certificate must match the webhook host.
CURLOPT_PROTOCOLSCURLPROTO_HTTPSNo protocol downgrade.
CURLOPT_CONNECTTIMEOUTmin(5, timeout)A dead host cannot hold a PHP worker for the full timeout.
CURLOPT_TIMEOUT1–30 secondsBounds the whole request.

Log redaction

The module log records the request URL, payload, HTTP status and an excerpt of the response. The URL is rewritten before it reaches the log:

Real URLLogged URL
https://contoso.webhook.office.com/webhookb2/abc@def/IncomingWebhook/123/SECREThttps://contoso.webhook.office.com/webhookb2/abc@def/IncomingWebhook/123/[redacted]
https://prod-12.westeurope.logic.azure.com/workflows/abc/triggers/manual/paths/invoke?api-version=1&sig=SECREThttps://prod-12.westeurope.logic.azure.com/workflows/abc/triggers/manual/paths/[redacted]?[redacted]

The payload is logged so you can see what was sent, but the token and signature never are. Error text returned by Teams is truncated to 200 characters before logging or display.

Never paste a real webhook URL into a screenshot, a ticket, a commit or a chat. If it is exposed, delete the webhook or workflow in Teams, create a replacement and update the provider.

Data handling

  • No module tables. Provider settings live in tblnotificationproviders.settings; rules live in tblnotificationrules.
  • No client data is stored by the module. Notification content is built in memory for each delivery.
  • No telemetry. The only outbound request is the HTTPS POST to the configured webhook.
  • No theme or core edits. Everything ships inside modules/notifications/MicrosoftTeams/.
  • Payload logging is opt-in. Module logging is controlled by WHMCS and should be off outside troubleshooting.

Teams-side permissions

The module needs no Microsoft Graph permission, no app registration and no admin consent. Access is governed by the webhook itself:

  • Workflows — the workflow is owned by the user who created it. Keep at least one co-owner so it is not orphaned when that user leaves.
  • Legacy connector — any member who can configure connectors for the channel can create or remove the webhook.
  • Tenant policy — an administrator can disable connectors or Workflows across the tenant. The module then receives HTTP 401 or 403 and reports it clearly.
  • Channel membership — the webhook posts as the workflow or connector identity, not as the administrator.

When to allow a custom host

Allow Custom Host is off by default. Enable it only when:

  • Your tenant uses a national or sovereign cloud domain that is not in the standard allowlist.
  • Outbound traffic passes through a trusted reverse proxy that rewrites the webhook host.

HTTPS, certificate verification and the no-redirect policy still apply. Do not enable it to make an unrelated URL work.

Security checklist

  • Use a dedicated Teams channel for WHMCS alerts, not a general chat.
  • Restrict who can edit the provider settings in WHMCS.
  • Keep module logging off except while diagnosing.
  • Rotate the workflow or webhook if a staff member with access leaves.
  • Review the module log for HTTP 401 and 403 responses, which can indicate a revoked URL.
  • Keep WHMCS, PHP and the CA bundle up to date.