Webhook alerts
Configure Slack, PagerDuty, Webex, and generic HMAC webhooks so the gateway can ping a chat or incident channel when high-severity events fire.
defenseclaw setup webhook manages the notifier webhooks the gateway calls when an event meets your minimum severity. Four types are supported. Each one can be set up with prompts or with flags only.
Notifiers and telemetry destinations
There are two separate webhook surfaces:
- Notifiers (
defenseclaw setup webhook) — chat/incident pings shaped to the destination's API (Slack blocks, PagerDuty Events v2, Webexmessages, or generic JSON). Filtered by severity and deduplicated. This page. - HTTP JSONL telemetry destinations (
defenseclaw setup observability add webhook) — canonical v8 log projections posted as JSON Lines. Omitted policy selects every collected log bucket;send/routesand destination redaction can narrow it. It has an independent bounded queue and is intended for SIEMs and data lakes.
Pick the surface that matches the consumer. Most installs run one notifier (Slack) and zero or more independent telemetry destinations.
The four webhook types
Prop
Type
Three worked examples
Slack incoming webhooks carry the secret in the URL itself, so you do not need a --secret-env:
defenseclaw setup webhook add slack \
--name slack-alerts \
--url https://hooks.slack.com/services/T000/B000/XXXXXX \
--min-severity HIGH \
--non-interactiveThe name is derived from the type and host. Test it without posting to the channel by using --dry-run, then send a real test when you're happy:
defenseclaw setup webhook test slack-alerts --dry-run
defenseclaw setup webhook test slack-alertsPagerDuty Events v2 needs a routing key. Store it with keys set (hidden
prompt, saved to ~/.defenseclaw/.env) and point the webhook at the env var's
name:
defenseclaw keys set DEFENSECLAW_PD_ROUTING_KEY
defenseclaw setup webhook add pagerduty \
--name pd-prod \
--url https://events.pagerduty.com/v2/enqueue \
--secret-env DEFENSECLAW_PD_ROUTING_KEY \
--min-severity HIGH \
--non-interactiveThe gateway reads the key from its environment, which includes ~/.defenseclaw/.env, when it starts. After you rotate the key, run defenseclaw-gateway restart.
For SIEM or SOAR platforms that accept a generic POST with a signature. Store the shared secret in DEFENSECLAW_SIEM_SECRET first:
defenseclaw keys set DEFENSECLAW_SIEM_SECRET
defenseclaw setup webhook add generic \
--name siem \
--url https://siem.example.com/defenseclaw \
--secret-env DEFENSECLAW_SIEM_SECRET \
--events block,guardrail \
--min-severity MEDIUM \
--non-interactiveThe receiver validates the signature by recomputing the hex
HMAC-SHA256(secret, body) and comparing it to the X-Hub-Signature-256
header, which has the form sha256=<hex>.
A dry run shows the payload and the headers without sending anything:
Testing webhook siem [generic] -> https://siem.example.com/***
(dry-run) formatting only, no delivery
Payload: 311 bytes
Preview: {"webhook_type":"defenseclaw_enforcement","defenseclaw_version":"1.0","event":{"id":"synthetic-8fd159624404","timestamp":"2026-10-03T04:09:51Z","action":"webhoo
Headers:
Content-Type: application/json
User-Agent: defenseclaw-cli/webhook-test
X-Hub-Signature-256: <redacted>
OK Result: dry-run OKA connector-hook block names the rule that fired. The event's details carry rule=<id> next to the redacted reason, and defenseclaw_rule gives the same label the agent sees, for example rule VB2-MARKER-BLOCK: Marker command. Titles appear only for compiled-in and loaded rule-pack rules; the matched content stays redacted.
All seven subcommands
Prop
Type
Flag reference for add
| Flag | Default | Notes |
|---|---|---|
--name <id> | derived from type + URL host | Friendly identifier shown in list and audit. |
--url <url> | (required) | Validated against the SSRF guard at write time and again at delivery. |
--secret-env <ENV> | required for pagerduty and webex | The name of an env var, never the literal secret. It must look like an env var name (A-Z, 0-9, _). |
--room-id <id> | (required for webex) | Webex room/space identifier. |
--min-severity INFO|LOW|MEDIUM|HIGH|CRITICAL | HIGH | Events below the floor are dropped. Case-insensitive. |
--events a,b,c | (all categories) | Allow-list of event categories: block, scan, guardrail, drift, health. |
--timeout-seconds <n> | 10 | Per-delivery timeout. |
--cooldown-seconds <n> | 300 (runtime default) | Dedup window. 0 disables dedup; omit to use the runtime default. |
--enabled / --disabled | --enabled | Initial state. |
--connector <name> | (global) | Scope the webhook to one connector. That connector's events go to its own webhooks when it has any, and to the global webhooks otherwise. list and remove take the same option. |
--dry-run | off | Print the YAML diff without writing. |
--non-interactive | off | Required for CI; a missing required field exits non-zero with a message such as error: pagerduty: --secret-env is required. |
Env var names the interactive prompt suggests for --secret-env:
| Type | Suggested --secret-env |
|---|---|
slack | (none — secret is in the URL) |
pagerduty | DEFENSECLAW_PD_ROUTING_KEY |
webex | DEFENSECLAW_WEBEX_TOKEN |
generic | asks whether to sign with HMAC first, then suggests DEFENSECLAW_WEBHOOK_SECRET |
SSRF guard
Every URL is checked against the same SSRF guard the gateway runs at delivery time:
- The scheme is
http://orhttps://, and the host parses. - The host resolves to a public address. Private (RFC 1918 and IPv6 ULA), link-local, loopback, cloud-metadata and carrier-grade NAT (100.64.0.0/10) addresses are rejected.
DEFENSECLAW_WEBHOOK_ALLOW_LOCALHOST=1allowslocalhostand loopback addresses only.DEFENSECLAW_ALLOW_CGNAT=1allows the 100.64.0.0/10 range only. Every other private range stays blocked.- No credentials in the URL (
https://user:pass@…); they belong in--secret-env.
error: IP 10.0.0.5 is a private or reserved address; webhooks must reach a public address so events can't be sent to internal services (SSRF guard). Use a public endpoint or relay.The check runs at add time and again at delivery time, which catches hand edits to config.yaml.
Verifying a webhook with test
test sends a synthetic event with a new event ID each time, so receivers do not deduplicate it:
defenseclaw setup webhook test pd-prodThe output includes:
- The formatted payload bytes count and a 160-byte preview.
- Every header DefenseClaw sent; the HMAC signature for
genericis shown as<redacted>. - The HTTP status returned by the receiver.
- A
setup-webhookaudit event withname=pd-prod type=pagerduty ok=True, recorded when the gateway is running.
To format the payload without sending it:
defenseclaw setup webhook test pd-prod --dry-runCommon gotchas
See also
- Webhook CLI source (
cmd_setup_webhook.py): every subcommand, validator and helper. internal/gateway/webhook.go— the dispatcher, dedup logic, and HMAC implementation.- Reference → CLI — the CLI command catalog.
- Observability → Splunk — to export every event, with no severity floor, as a telemetry destination.
Splunk
defenseclaw setup splunk configures three independent pipelines — a local Splunk in Docker for demos, remote Splunk Enterprise through HEC, and Splunk Observability Cloud through OTLP.
Redaction
Configure centralized, field-aware redaction independently for local history, buckets, and export destinations in DefenseClaw observability v8.