Webhook Notifications

Webhook Notifications

The following files were used as context for generating this wiki page:

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:

  1. Scan Completion: WSHawkV2.run_heuristic_scan() finishes all vulnerability tests
  2. Report Generation: HTML reports are created and saved
  3. Integration Phase: Configuration-based integrations are processed
  4. 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

  1. Navigate to your Slack workspace's App Directory
  2. Search for "Incoming Webhooks" and add to workspace
  3. Select target channel (e.g., #security-alerts)
  4. 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

  1. Open Discord server settings
  2. Navigate to Integrations → Webhooks
  3. Click "New Webhook"
  4. Name it (e.g., "WSHawk Scanner")
  5. Select target channel
  6. 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

  1. Open Teams channel
  2. Click "•••" (More options) → Connectors
  3. Search for "Incoming Webhook" and configure
  4. Name the webhook (e.g., "WSHawk Alerts")
  5. Upload icon (optional)
  6. 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.enabled is true
  • 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:

  1. 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"
    
  2. Use environment variables:

    export WSHAWK_WEBHOOK_URL='...'
    
  3. 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