DocsGeneric Webhook
Webhook

Generic Webhook

The WEBHOOK alert channel sends a signed HTTP POST to any URL you configure: point it at Wazuh, Cortex XSOAR, CrowdStrike, SentinelOne, Elastic, or anything else with an HTTP input. It's the same channel type used for every alert this platform sends beyond email, Slack, Teams, and PagerDuty, which have first-class formatters; this is the one that covers everything else.

1. Configure the channel

In Settings → Alert channels, add a Generic Webhook channel with your endpoint URL and (recommended) a signing secret. Every alert, starting with watchlist score spikes, gets POSTed to that URL as it fires; more triggers land here as they ship.

2. Payload schema

Content-Type is application/json. The top-level envelope (event, id, timestamp) stays stable across alert types; data is specific to the event.

{
  "event": "watchlist.score_spike",
  "id": "a1b2c3d4-...",
  "timestamp": "2026-08-21T13:45:00.000Z",
  "data": {
    "ioc": "185.220.101.45",
    "type": "ip",
    "oldScore": 10,
    "newScore": 85,
    "verdict": "VT: 12/70 engines flagged | OTX: 3 pulses"
  }
}

3. Verify the signature

If you set a secret, every request carries an X-ThreatIntellix-Signature header: an HMAC-SHA256 of the raw request body, hex-encoded, prefixed with sha256=. Compute it against the raw, unparsed body; verifying against a re-serialized JSON object will not match if key order or whitespace differs.

Node.js

const crypto = require('crypto');

function isValidSignature(rawBody, signatureHeader, secret) {
  // signatureHeader looks like "sha256=<hex>"
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signatureHeader),
    Buffer.from(expected)
  );
}

Python

import hashlib
import hmac

def is_valid_signature(raw_body: bytes, signature_header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature_header, expected)

4. A 2xx response is all we need

Any 2xx status is treated as a successful delivery. Non-2xx responses are logged server-side but not retried in this version; if your endpoint has downtime, alerts sent during that window aren't redelivered. Design your receiver to be fast and reliable, or front it with a queue if you need guaranteed processing.

Setup notes for common tools

  • Wazuh: use a custom integration script that reads from a local HTTP listener, or a webhook-to-syslog bridge if you need it as a decoded event.
  • Cortex XSOAR: create an incoming webhook integration instance pointed at a XSOAR-hosted URL; map the data fields to incident fields.
  • CrowdStrike / SentinelOne: both support generic webhook/HTTP event connectors under their respective integration marketplaces; use the payload schema above as the field-mapping reference.
  • Elastic: the HTTP Endpoint input in Elastic Agent (or a Logstash HTTP input) accepts this payload directly; index on data.ioc for correlation.
  • Anything else with an HTTP input works the same way; there's nothing ThreatIntellix-specific about the delivery mechanism, only the payload shape above.