Webhooks API

Receive events from external security tools.

Endpoint

POST /api/webhooks/:source

Where :source identifies the sending system (e.g., email-gateway, edr, siem).

Authentication

Webhooks are authenticated via HMAC signatures:

X-Webhook-Signature: sha256=abc123...
X-Webhook-Timestamp: 1705320000

Registering Webhook Sources

Via CLI

tw-cli webhook add email-gateway \
  --secret "your-secret-key" \
  --auto-triage true \
  --playbook phishing_triage

Via API

curl -X POST "http://localhost:8080/api/webhooks" \
  -H "Authorization: Bearer tw_xxx" \
  -d '{
    "source": "email-gateway",
    "secret": "your-secret-key",
    "auto_triage": true,
    "playbook": "phishing_triage"
  }'

Payload Formats

Generic Format

{
  "event_type": "security_alert",
  "timestamp": "2024-01-15T10:00:00Z",
  "source": "email-gateway",
  "data": {
    "alert_id": "alert-123",
    "severity": "high",
    "details": {...}
  }
}

Microsoft Defender for Office 365

{
  "eventType": "PhishingEmail",
  "id": "AAMkAGI2...",
  "creationTime": "2024-01-15T10:00:00Z",
  "severity": "high",
  "category": "Phish",
  "entityType": "Email",
  "data": {
    "sender": "phisher@malicious.com",
    "subject": "Urgent Action Required",
    "recipients": ["user@company.com"]
  }
}

CrowdStrike Falcon

{
  "metadata": {
    "eventType": "DetectionSummaryEvent",
    "eventCreationTime": 1705320000000
  },
  "event": {
    "DetectId": "ldt:abc123",
    "Severity": 4,
    "HostnameField": "WORKSTATION-01",
    "DetectName": "Malicious File Detected"
  }
}

Splunk Alert

{
  "result": {
    "host": "server-01",
    "source": "WinEventLog:Security",
    "sourcetype": "WinEventLog",
    "_raw": "...",
    "EventCode": "4625"
  },
  "search_name": "Failed Login Alert",
  "trigger_time": 1705320000
}

Response

Success

{
  "status": "accepted",
  "incident_id": "550e8400-e29b-41d4-a716-446655440000",
  "incident_number": "INC-2024-0001"
}

Queued for Processing

{
  "status": "queued",
  "queue_id": "queue-abc123",
  "message": "Event queued for processing"
}

Configuring Auto-Triage

When auto_triage is enabled, incidents created from webhooks are automatically triaged:

# webhook_config.yaml
sources:
  email-gateway:
    secret: "${EMAIL_GATEWAY_SECRET}"
    auto_triage: true
    playbook: phishing_triage
    severity_mapping:
      critical: critical
      high: high
      medium: medium
      low: low

  edr:
    secret: "${EDR_SECRET}"
    auto_triage: true
    playbook: malware_triage

Testing Webhooks

Send Test Event

# Generate signature
TIMESTAMP=$(date +%s)
BODY='{"event_type":"test","data":{}}'
SIGNATURE=$(echo -n "${TIMESTAMP}.${BODY}" | openssl dgst -sha256 -hmac "your-secret")

# Send request
curl -X POST "http://localhost:8080/api/webhooks/email-gateway" \
  -H "Content-Type: application/json" \
  -H "X-Webhook-Signature: sha256=${SIGNATURE}" \
  -H "X-Webhook-Timestamp: ${TIMESTAMP}" \
  -d "${BODY}"

Verify Configuration

tw-cli webhook test email-gateway

Error Handling

Invalid Signature

{
  "error": {
    "code": "invalid_signature",
    "message": "Webhook signature verification failed"
  }
}

Unknown Source

{
  "error": {
    "code": "unknown_source",
    "message": "Webhook source 'unknown' is not registered"
  }
}

Replay Attack

{
  "error": {
    "code": "timestamp_expired",
    "message": "Webhook timestamp is too old (>5 minutes)"
  }
}

Monitoring Webhooks

Metrics

# Webhook receive rate
rate(webhook_received_total[5m])

# Error rate by source
rate(webhook_errors_total[5m])

Logs

tw-cli logs --filter webhook --tail 100