Docs/Build/Webhooks

Webhooks.

Outbound: a generic webhook connector with a deterministic HMAC signature over the payload. Inbound: provider signatures verified fail-closed with a five-minute timestamp window.

Outbound header X-SignatureAlgorithm HMAC-SHA256Timestamp X-TimestampUpdated September 2026

Outbound events

Configure a Generic webhook under Integrations → Ticketing with a URL, an optional shared secret, an optional signature header name (default X-Signature), a signature prefix (default sha256=) and any static extra headers. The connector posts finding events as JSON.

POST https://hooks.example.com/securityvault
Content-Type: application/json
User-Agent: ESOS-Webhook/1.0
X-Timestamp: 2026-09-13T09:12:41.118Z
X-Signature: sha256=7c4a…d3f1

{
  "event": "esos.finding",
  "timestamp": "2026-09-13T09:12:41.118Z",
  "payload": { "finding_id": "…", "severity": "high", "title": "…", "entity": { … } }
}

Verifying the signature

The signature is HMAC-SHA256 over the canonical JSON of the payload object only — keys sorted, no whitespace — so identical payloads always produce identical signatures and receivers can de-duplicate replays. The wall-clock timestamp travels in X-Timestamp for staleness checks.

# python
import hmac, hashlib, json
payload = json.dumps(body["payload"], sort_keys=True, separators=(",", ":")).encode()
expected = "sha256=" + hmac.new(secret, payload, hashlib.sha256).hexdigest()
ok = hmac.compare_digest(expected, request.headers["X-Signature"])
Always compare in constant time and reject when X-Timestamp is older than your tolerance.

Inbound webhooks

Provider webhooks that reach SecurityVault — GitHub, GitLab, Bitbucket, Azure DevOps, Slack, Microsoft Teams and ticketing systems — are verified before any payload is trusted: provider-specific HMAC schemes, constant-time comparison, and a ±5-minute timestamp window where the provider supplies one. Verification never raises; a malformed input is a reject. Ticketing webhooks additionally carry a per-organisation, per-provider key with X-SV-Body-Signature and an X-SV-Nonce replay guard, and fail closed when signing is required.

Delivery and retries

Outbound notifications go through a retrying dispatcher with an outbox and a dead-letter queue, so a receiver outage delays delivery rather than losing it. Non-2xx responses are retried with exponential backoff; the delivery record — attempted, delivered, failed — is visible on the integration.