Webhook Notifications
Webhook Notifications
The following files were used as context for generating this wiki page:
- .github/workflows/ghcr-publish.yml
- README.md
- RELEASE_3.0.0.md
- RELEASE_SUMMARY.md
- docs/V3_COMPLETE_GUIDE.md
- requirements.txt
- wshawk/advanced_cli.py
- wshawk/scanner_v2.py
Purpose and Scope
This document explains how to configure webhook notifications in WSHawk to send real-time alerts about security findings to collaboration platforms. Webhook notifications enable security teams to receive immediate alerts when vulnerabilities are discovered during WebSocket security scans.
For information about other integration options, see Jira Integration for issue tracking and DefectDojo Integration for vulnerability management. For general configuration principles, see Configuration System. For report export formats beyond webhooks, see Report Formats and Export.
Sources: README.md:31, RELEASE_SUMMARY.md:34
Supported Platforms
WSHawk provides native support for three major collaboration platforms plus a generic webhook format:
| Platform | Format | Auto-Detection | Rich Formatting | |----------|--------|----------------|-----------------| | Slack | Slack Block Kit | Yes (hooks.slack.com) | Yes | | Discord | Discord Embeds | Yes (discord.com, discordapp.com) | Yes | | Microsoft Teams | Adaptive Cards | Yes (office.com, webhook.office) | Yes | | Generic | JSON payload | Manual | Configurable |
Each platform receives structured notifications including:
- CVSS v3.1 scores for discovered vulnerabilities
- Severity classification (CRITICAL, HIGH, MEDIUM, LOW)
- Target WebSocket URL
- Vulnerability counts by confidence level
- Scan statistics (messages sent/received, duration)
- Direct links to generated HTML reports
Sources: advanced_cli.py:66-69, advanced_cli.py:271-278
Configuration Methods
CLI Configuration
The wshawk-advanced command provides webhook flags for immediate use:
# Basic webhook notification
wshawk-advanced ws://target.com --webhook https://hooks.slack.com/services/YOUR/WEBHOOK/URL
# Explicit platform specification
wshawk-advanced ws://target.com --webhook URL --webhook-platform slack
# Combined with other features
wshawk-advanced ws://target.com --webhook URL --playwright --full
Available CLI Flags:
--webhook URL: Webhook endpoint URL--webhook-platform {slack,discord,teams,generic}: Platform type (defaults to auto-detect)
Sources: advanced_cli.py:66-69
Configuration File (wshawk.yaml)
For persistent webhook configuration, use the hierarchical configuration system:
integrations:
webhooks:
enabled: true
url: "env:WSHAWK_WEBHOOK_URL" # Secret resolution
platform: "slack" # or discord, teams, generic
# Optional: Platform-specific settings
slack:
channel: "#security-alerts"
username: "WSHawk Scanner"
icon_emoji: ":eagle:"
discord:
username: "WSHawk"
avatar_url: "https://example.com/wshawk-icon.png"
teams:
theme_color: "FF0000" # Red for critical findings
Generate a configuration template:
python3 -m wshawk.config --generate
Sources: README.md:137-150, advanced_cli.py:86-97
Environment Variables
Webhook URLs containing sensitive tokens can be resolved from environment variables:
# Set the webhook URL
export WSHAWK_WEBHOOK_URL='https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX'
# Configuration file references it
# wshawk.yaml:
# webhooks:
# url: "env:WSHAWK_WEBHOOK_URL"
# Run scan
wshawk-advanced ws://target.com
This approach prevents credential exposure in version-controlled configuration files.
Sources: README.md:137-150
Webhook Notification Flow
Integration Architecture
graph TB
Scanner["WSHawkV2 Scanner<br/>scanner_v2.py"]
Results["Scan Results<br/>vulnerabilities list<br/>scan_info dict"]
Config["WSHawkConfig<br/>config.py"]
Notifier["WebhookNotifier<br/>integrations/webhook.py"]
subgraph "Platform Detection"
AutoDetect["Auto-Detection Logic<br/>URL pattern matching"]
PlatformRouter["Platform Router"]
end
subgraph "Formatters"
SlackFmt["Slack Block Formatter<br/>Block Kit JSON"]
DiscordFmt["Discord Embed Formatter<br/>Embed objects"]
TeamsFmt["Teams Card Formatter<br/>Adaptive Cards"]
GenericFmt["Generic Formatter<br/>Plain JSON"]
end
subgraph "Delivery"
ResilientSession["ResilientSession<br/>Exponential backoff<br/>Circuit breaker"]
HTTP["HTTP POST<br/>aiohttp"]
end
Scanner -->|"run_heuristic_scan()<br/>complete"| Results
Scanner --> Config
Config -->|"webhooks.enabled<br/>webhooks.url"| Notifier
Results --> Notifier
Notifier --> AutoDetect
AutoDetect -->|"hooks.slack.com"| SlackFmt
AutoDetect -->|"discord.com"| DiscordFmt
AutoDetect -->|"office.com"| TeamsFmt
AutoDetect -->|"manual/other"| GenericFmt
SlackFmt --> ResilientSession
DiscordFmt --> ResilientSession
TeamsFmt --> ResilientSession
GenericFmt --> ResilientSession
ResilientSession --> HTTP
HTTP -->|"200 OK"| Success["Log success"]
HTTP -->|"429/5xx"| Retry["Exponential backoff<br/>Retry logic"]
Sources: scanner_v2.py:807-850, advanced_cli.py:267-281
Notification Trigger Points
Webhooks are invoked automatically after scan completion, following this sequence:
- Scan Completion:
WSHawkV2.run_heuristic_scan()finishes all vulnerability tests - Report Generation: HTML reports are created and saved
- Integration Phase: Configuration-based integrations are processed
- Webhook Delivery: Notifications are sent via
WebhookNotifier.notify()
sequenceDiagram
participant Scanner as WSHawkV2
participant Config as WSHawkConfig
participant Notifier as WebhookNotifier
participant Platform as Slack/Discord/Teams
Scanner->>Scanner: run_heuristic_scan()
Scanner->>Scanner: test_sql_injection_v2()
Scanner->>Scanner: test_xss_v2()
Scanner->>Scanner: [other tests...]
Scanner->>Config: get('integrations.webhooks')
Config-->>Scanner: webhook_config
alt Webhooks Enabled
Scanner->>Notifier: notify(vulns, scan_info)
Notifier->>Notifier: detect_platform(url)
Notifier->>Notifier: format_message(platform)
Notifier->>Platform: POST /webhook
Platform-->>Notifier: 200 OK
Notifier-->>Scanner: notification_sent
end
Scanner->>Scanner: Log success
Sources: scanner_v2.py:807-850, advanced_cli.py:267-281
Message Format and Content
Common Payload Structure
All webhook notifications include standardized fields regardless of platform:
| Field | Type | Description | Example |
|-------|------|-------------|---------|
| target | string | WebSocket URL scanned | ws://example.com/api |
| vulnerabilities_found | integer | Total vulnerability count | 12 |
| severity_breakdown | object | Count by severity | {"CRITICAL": 2, "HIGH": 5} |
| scan_duration | float | Scan time in seconds | 127.3 |
| messages_exchanged | object | Traffic statistics | {"sent": 2304, "received": 2298} |
| timestamp | string | Scan completion time | 2024-01-15T14:32:10Z |
| report_link | string | Path to HTML report | wshawk_report_20240115_143210.html |
Platform-Specific Formatting
Slack Block Kit Format
Slack notifications use Block Kit for rich, interactive messages:
{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "š¦
WSHawk Security Scan Complete"
}
},
{
"type": "section",
"fields": [
{"type": "mrkdwn", "text": "*Target:*\nws://example.com/api"},
{"type": "mrkdwn", "text": "*Vulnerabilities:*\n12 found"}
]
},
{
"type": "section",
"fields": [
{"type": "mrkdwn", "text": "*Critical:* 2"},
{"type": "mrkdwn", "text": "*High:* 5"},
{"type": "mrkdwn", "text": "*Medium:* 3"},
{"type": "mrkdwn", "text": "*Low:* 2"}
]
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "š *Scan Statistics*\n⢠Duration: 127.3s\n⢠Messages Sent: 2304\n⢠Messages Received: 2298"
}
}
]
}
Visual Features:
- Header block with emoji for visibility
- Color-coded severity counts
- Inline statistics with emoji indicators
- Optional action buttons for report access
Sources: README.md:31, RELEASE_SUMMARY.md:34
Discord Embed Format
Discord notifications use embedded messages with color-coding:
{
"embeds": [
{
"title": "š¦
WSHawk Security Scan",
"color": 15158332,
"fields": [
{"name": "Target", "value": "ws://example.com/api", "inline": true},
{"name": "Total Findings", "value": "12", "inline": true},
{"name": "Critical", "value": "2", "inline": true},
{"name": "High", "value": "5", "inline": true},
{"name": "Medium", "value": "3", "inline": true},
{"name": "Low", "value": "2", "inline": true},
{"name": "Duration", "value": "127.3s", "inline": true},
{"name": "Messages", "value": "2304 sent / 2298 received", "inline": false}
],
"timestamp": "2024-01-15T14:32:10Z",
"footer": {"text": "WSHawk v3.0.0"}
}
]
}
Visual Features:
- Embed color matches severity (red for critical findings)
- Inline fields for compact display
- ISO 8601 timestamp
- Footer with WSHawk version
Sources: RELEASE_SUMMARY.md:34
Microsoft Teams Adaptive Card Format
Teams notifications use Adaptive Cards for rich, actionable content:
{
"type": "message",
"attachments": [
{
"contentType": "application/vnd.microsoft.card.adaptive",
"content": {
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.4",
"body": [
{
"type": "TextBlock",
"text": "WSHawk Security Scan Complete",
"weight": "Bolder",
"size": "Large"
},
{
"type": "FactSet",
"facts": [
{"title": "Target", "value": "ws://example.com/api"},
{"title": "Vulnerabilities", "value": "12 found"},
{"title": "Critical", "value": "2"},
{"title": "High", "value": "5"},
{"title": "Scan Duration", "value": "127.3s"}
]
}
]
}
}
]
}
Visual Features:
- Structured FactSet for key-value data
- Themeable color based on severity
- Optional action buttons
- Rich text formatting support
Sources: RELEASE_SUMMARY.md:34
Platform-Specific Setup
Slack Incoming Webhooks
Step 1: Create Incoming Webhook
- Navigate to your Slack workspace's App Directory
- Search for "Incoming Webhooks" and add to workspace
- Select target channel (e.g.,
#security-alerts) - Copy the generated webhook URL (format:
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX)
Step 2: Configure WSHawk
# CLI method
wshawk-advanced ws://target.com \
--webhook https://hooks.slack.com/services/YOUR/WEBHOOK/URL
# Environment variable method
export WSHAWK_WEBHOOK_URL='https://hooks.slack.com/services/YOUR/WEBHOOK/URL'
wshawk-advanced ws://target.com
Step 3: Verify
Run a test scan. You should receive a notification in the configured Slack channel within seconds of scan completion.
Sources: advanced_cli.py:273-274
Discord Webhooks
Step 1: Create Discord Webhook
- Open Discord server settings
- Navigate to Integrations ā Webhooks
- Click "New Webhook"
- Name it (e.g., "WSHawk Scanner")
- Select target channel
- Copy webhook URL (format:
https://discord.com/api/webhooks/000000000000000000/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX)
Step 2: Configure WSHawk
# wshawk.yaml
integrations:
webhooks:
enabled: true
url: "https://discord.com/api/webhooks/YOUR/WEBHOOK/ID/TOKEN"
platform: "discord" # Auto-detected from URL
discord:
username: "WSHawk Security Scanner"
avatar_url: "https://example.com/wshawk-avatar.png"
Sources: advanced_cli.py:275-276
Microsoft Teams Webhooks
Step 1: Create Teams Incoming Webhook
- Open Teams channel
- Click "ā¢ā¢ā¢" (More options) ā Connectors
- Search for "Incoming Webhook" and configure
- Name the webhook (e.g., "WSHawk Alerts")
- Upload icon (optional)
- Copy the webhook URL (format:
https://outlook.office.com/webhook/...)
Step 2: Configure WSHawk
# CLI method with auto-detection
wshawk-advanced ws://target.com \
--webhook https://outlook.office.com/webhook/YOUR-WEBHOOK-ID
# Configuration file method
# wshawk.yaml:
# integrations:
# webhooks:
# url: "env:TEAMS_WEBHOOK_URL"
# platform: "teams"
Sources: advanced_cli.py:277-278
Generic Webhooks (Custom Endpoints)
For custom webhook endpoints or third-party services not natively supported:
Payload Structure:
{
"event_type": "wshawk_scan_complete",
"timestamp": "2024-01-15T14:32:10Z",
"scan_data": {
"target": "ws://example.com/api",
"vulnerabilities": {
"total": 12,
"by_severity": {
"CRITICAL": 2,
"HIGH": 5,
"MEDIUM": 3,
"LOW": 2
}
},
"statistics": {
"duration_seconds": 127.3,
"messages_sent": 2304,
"messages_received": 2298
},
"reports": {
"html": "wshawk_report_20240115_143210.html",
"json": "wshawk_report_20240115_143210.json"
}
},
"metadata": {
"wshawk_version": "3.0.0",
"scanner_features": ["playwright", "oast", "smart_payloads"]
}
}
Configuration:
integrations:
webhooks:
enabled: true
url: "https://your-service.com/api/webhooks"
platform: "generic"
# Custom headers (optional)
headers:
Authorization: "env:CUSTOM_WEBHOOK_TOKEN"
Content-Type: "application/json"
Sources: advanced_cli.py:268-281
Platform Auto-Detection
WSHawk automatically detects the webhook platform based on URL patterns, eliminating the need for explicit configuration in most cases.
Detection Logic
graph TD
URL["Webhook URL"]
Check1{"Contains<br/>'slack.com' or<br/>'hooks.slack'?"}
Check2{"Contains<br/>'discord.com' or<br/>'discordapp.com'?"}
Check3{"Contains<br/>'office.com' or<br/>'webhook.office'?"}
Slack["Platform: slack<br/>Formatter: SlackBlockFormatter"]
Discord["Platform: discord<br/>Formatter: DiscordEmbedFormatter"]
Teams["Platform: teams<br/>Formatter: TeamsCardFormatter"]
Generic["Platform: generic<br/>Formatter: GenericJSONFormatter"]
URL --> Check1
Check1 -->|Yes| Slack
Check1 -->|No| Check2
Check2 -->|Yes| Discord
Check2 -->|No| Check3
Check3 -->|Yes| Teams
Check3 -->|No| Generic
Implementation Reference: advanced_cli.py:271-278
Manual Override
To bypass auto-detection:
# Force specific platform
wshawk-advanced ws://target.com \
--webhook https://custom-endpoint.com/hook \
--webhook-platform slack
This is useful when:
- Using a proxy/gateway that obscures the actual platform
- Custom webhook relay services
- Testing different message formats
Sources: advanced_cli.py:68-69
Integration with Scan Lifecycle
Timing and Triggering
Webhook notifications are sent at specific points in the scan lifecycle:
graph LR
Start["Scan Start<br/>run_heuristic_scan()"]
Tests["Vulnerability Tests<br/>SQL, XSS, XXE, etc."]
Session["Session Tests<br/>SessionHijackingTester"]
Reports["Report Generation<br/>HTML/JSON/SARIF"]
Integrations["Automated Integrations<br/>- Jira<br/>- DefectDojo<br/>- Webhooks"]
Complete["Scan Complete"]
Start --> Tests
Tests --> Session
Session --> Reports
Reports --> Integrations
Integrations --> Complete
Sources: scanner_v2.py:593-850
Conditional Notification
Webhooks can be configured to trigger only for specific severity thresholds:
integrations:
webhooks:
enabled: true
url: "env:WEBHOOK_URL"
# Only notify for high-severity findings
severity_threshold: "HIGH" # CRITICAL, HIGH, MEDIUM, LOW
# Minimum vulnerability count to trigger
min_vulnerabilities: 1
This prevents notification fatigue in high-volume scanning environments.
Sources: scanner_v2.py:807-850
Resilience and Error Handling
Retry Logic
Webhook delivery uses the ResilientSession component to handle network failures gracefully:
stateDiagram-v2
[*] --> Attempt
Attempt --> Success: 200 OK
Attempt --> TransientError: 429/5xx
Attempt --> PermanentError: 400/401/403/404
TransientError --> Backoff: Calculate exponential delay
Backoff --> CircuitCheck: Check circuit breaker state
CircuitCheck --> Attempt: CLOSED (retry)
CircuitCheck --> Failed: OPEN (skip)
Success --> [*]
PermanentError --> Failed: Log error
Failed --> [*]
Retry Configuration:
- Maximum Attempts: 3 (configurable)
- Base Delay: 1 second
- Exponential Factor: 2x per attempt
- Jitter: ±20% randomization
- Circuit Breaker: Opens after 5 consecutive failures
Sources: RELEASE_SUMMARY.md:9-13, scanner_v2.py:807-850
Error Classification
| HTTP Status | Classification | Action | |-------------|----------------|--------| | 200, 204 | Success | Log success, continue | | 429 | Rate limit | Exponential backoff, retry | | 500, 502, 503 | Transient error | Backoff, retry up to max attempts | | 400 | Bad request | Log error, fail (no retry) | | 401, 403 | Authentication | Log error, fail (no retry) | | 404 | Not found | Log error, fail (no retry) |
Sources: RELEASE_SUMMARY.md:9-13
Troubleshooting
Common Issues
Issue: Webhook not triggered
# Check configuration
python3 -m wshawk.config --validate
# Enable debug logging
export WSHAWK_LOG_LEVEL=DEBUG
wshawk-advanced ws://target.com --webhook URL
Verify:
integrations.webhooks.enabledistrue- Webhook URL is correctly formatted
- No typos in environment variable names
Issue: 401 Unauthorized
Some webhook services require authentication headers:
integrations:
webhooks:
url: "https://custom-service.com/webhook"
headers:
Authorization: "Bearer env:WEBHOOK_TOKEN"
Issue: Platform not auto-detected
Manually specify platform:
wshawk-advanced ws://target.com \
--webhook URL \
--webhook-platform slack
Issue: Circuit breaker OPEN
Reset by restarting the scan. Check target service health and reduce scan rate:
wshawk-advanced ws://target.com --rate 5 --webhook URL
Sources: advanced_cli.py:267-281
Testing Webhooks
Send a test notification without performing a full scan:
import asyncio
from wshawk.integrations.webhook import WebhookNotifier
async def test():
notifier = WebhookNotifier(
webhook_url="https://hooks.slack.com/services/YOUR/WEBHOOK",
platform="slack"
)
test_vulns = [
{
'type': 'SQL Injection',
'severity': 'HIGH',
'confidence': 'HIGH',
'description': 'Test vulnerability',
'payload': "' OR '1'='1",
}
]
scan_info = {
'target': 'ws://test.example.com',
'duration': 60.0,
'messages_sent': 100,
'messages_received': 100
}
await notifier.notify(test_vulns, scan_info)
asyncio.run(test())
Sources: advanced_cli.py:267-281
Security Considerations
Webhook URL Protection
Webhook URLs often contain sensitive tokens. Best practices:
-
Never commit webhook URLs to version control:
# wshawk.yaml - GOOD integrations: webhooks: url: "env:WSHAWK_WEBHOOK_URL" # wshawk.yaml - BAD # webhooks: # url: "https://hooks.slack.com/services/T123/B456/SECRET" -
Use environment variables:
export WSHAWK_WEBHOOK_URL='...' -
Restrict file permissions:
chmod 600 wshawk.yaml
Data in Transit
All webhook notifications are sent via HTTPS. WSHawk validates SSL certificates by default. To disable certificate validation (not recommended):
integrations:
webhooks:
verify_ssl: false # Only for testing
Sensitive Information
Webhook payloads may contain:
- Target URLs (may reveal internal hostnames)
- Payload samples (may contain test credentials)
- Response snippets (may contain sensitive data)
Configure notification verbosity:
integrations:
webhooks:
include_payloads: false # Omit actual payloads
include_responses: false # Omit response snippets
summary_only: true # Only counts and severities
Sources: README.md:137-150
Advanced Configuration
Multiple Webhooks
Send notifications to multiple destinations:
integrations:
webhooks:
- url: "env:SLACK_SECURITY_CHANNEL"
platform: "slack"
severity_threshold: "HIGH"
- url: "env:DISCORD_DEVOPS_CHANNEL"
platform: "discord"
severity_threshold: "CRITICAL"
- url: "env:TEAMS_MANAGEMENT_CHANNEL"
platform: "teams"
summary_only: true
Conditional Webhooks
Configure different webhooks for different scan contexts:
integrations:
webhooks:
production:
url: "env:PROD_WEBHOOK"
severity_threshold: "MEDIUM"
enabled: true
staging:
url: "env:STAGING_WEBHOOK"
severity_threshold: "LOW"
enabled: true
development:
url: "env:DEV_WEBHOOK"
enabled: false # Don't notify for dev scans
Activate by environment:
export WSHAWK_ENV=production
wshawk-advanced ws://target.com
Sources: README.md:137-150, advanced_cli.py:86-97
Code Reference Summary
Key Classes and Functions
| Component | Location | Purpose |
|-----------|----------|---------|
| WebhookNotifier | wshawk/integrations/webhook.py | Main webhook notification class |
| WSHawkV2.run_heuristic_scan() | wshawk/scanner_v2.py:593-850 | Integration trigger point |
| ResilientSession | wshawk/resilience/session.py | Retry and circuit breaker logic |
| CLI webhook flags | wshawk/advanced_cli.py:66-69 | Command-line interface |
| Webhook invocation | wshawk/advanced_cli.py:267-281 | CLI webhook execution |
| Platform detection | wshawk/advanced_cli.py:271-278 | URL-based platform identification |
| Configuration loading | wshawk/advanced_cli.py:86-97 | Config system integration |
Sources: scanner_v2.py:1-850, advanced_cli.py:1-299