WSHawkV2 Scanner Engine

WSHawkV2 Scanner Engine

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

Purpose and Scope

The WSHawkV2 class is the core orchestration engine for all offensive security testing in WSHawk. This page documents the scanner's architecture, initialization process, scanning lifecycle, and how it coordinates specialized analysis modules to detect vulnerabilities in WebSocket applications.

For information about the individual analysis modules (MessageAnalyzer, VulnerabilityVerifier, ServerFingerprinter), see Analysis and Verification Modules. For details on specific vulnerability detection techniques, see Vulnerability Detection Modules. For payload mutation strategies, see Payload Mutation and WAF Evasion.


Class Architecture

Component Overview

The WSHawkV2 class aggregates multiple specialized modules to perform comprehensive WebSocket security testing. The scanner follows a delegation pattern where each module handles a specific aspect of the scanning process.

Diagram: WSHawkV2 Component Architecture

graph TB
    Scanner["WSHawkV2<br/>(scanner_v2.py:28)"]
    
    subgraph "Analysis Modules"
        MA["MessageAnalyzer<br/>message_intelligence"]
        VV["VulnerabilityVerifier<br/>vulnerability_verifier"]
        SF["ServerFingerprinter<br/>server_fingerprint"]
    end
    
    subgraph "Session Management"
        SM["SessionStateMachine<br/>state_machine"]
        RL["TokenBucketRateLimiter<br/>rate_limiter"]
    end
    
    subgraph "Advanced Verification (Optional)"
        HV["HeadlessBrowserXSSVerifier<br/>headless_xss_verifier"]
        OAST["OASTProvider<br/>oast_provider"]
    end
    
    subgraph "Reporting"
        Rep["EnhancedHTMLReporter<br/>enhanced_reporter"]
    end
    
    subgraph "Testing"
        SHT["SessionHijackingTester<br/>session_hijacking_tester"]
    end
    
    Scanner --> MA
    Scanner --> VV
    Scanner --> SF
    Scanner --> SM
    Scanner --> RL
    Scanner --> HV
    Scanner --> OAST
    Scanner --> Rep
    Scanner --> SHT
    
    MA -.informs.-> VV
    SF -.provides context.-> Scanner
    RL -.controls rate.-> Scanner

Sources: wshawk/scanner_v2.py:1-76

Module Responsibilities

| Module | Purpose | Initialized At | |--------|---------|---------------| | MessageAnalyzer | Detects message format (JSON/XML/Binary), identifies injectable fields | scanner_v2.py:41 | | VulnerabilityVerifier | Verifies vulnerability patterns with confidence scoring | scanner_v2.py:42 | | ServerFingerprinter | Identifies backend technology stack (language, framework, database) | scanner_v2.py:43 | | SessionStateMachine | Tracks WebSocket connection state and authentication sequences | scanner_v2.py:44 | | TokenBucketRateLimiter | Controls request rate with adaptive throttling | scanner_v2.py:45-49 | | EnhancedHTMLReporter | Generates vulnerability reports with CVSS scores | scanner_v2.py:50 | | HeadlessBrowserXSSVerifier | Verifies XSS execution in real browser (optional) | scanner_v2.py:54 | | OASTProvider | Detects blind vulnerabilities via out-of-band callbacks (optional) | scanner_v2.py:58 | | SessionHijackingTester | Tests session security vulnerabilities | scanner_v2.py:594 |

Sources: wshawk/scanner_v2.py:28-76


Initialization and Configuration

Constructor Parameters

The WSHawkV2 constructor accepts the following parameters:

def __init__(self, url: str, headers: Optional[Dict] = None, 
             auth_sequence: Optional[str] = None,
             max_rps: int = 10):

| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | url | str | Required | Target WebSocket URL (ws:// or wss://) | | headers | Optional[Dict] | None | Additional HTTP headers for WebSocket handshake | | auth_sequence | Optional[str] | None | Path to YAML file containing authentication sequence | | max_rps | int | 10 | Maximum requests per second (rate limiting) |

Sources: wshawk/scanner_v2.py:33-35

Instance Variables

The scanner maintains several state variables throughout its lifecycle:

| Variable | Purpose | Initialized At | |----------|---------|---------------| | vulnerabilities | List of detected vulnerabilities | scanner_v2.py:38 | | messages_sent | Counter for sent messages | scanner_v2.py:65 | | messages_received | Counter for received messages | scanner_v2.py:66 | | learning_complete | Flag indicating learning phase status | scanner_v2.py:71 | | sample_messages | Messages collected during learning phase | scanner_v2.py:72 | | traffic_logs | Raw traffic logs for report generation | scanner_v2.py:75 | | start_time / end_time | Scan duration tracking | scanner_v2.py:67-68 |

Sources: wshawk/scanner_v2.py:33-76

Optional Features

Two advanced verification features can be toggled:

# Control headless browser verification
scanner.use_headless_browser = True  # Default: True
scanner.headless_verifier = None     # Lazy-initialized

# Control OAST for blind vulnerabilities
scanner.use_oast = True              # Default: True
scanner.oast_provider = None         # Lazy-initialized

Sources: wshawk/scanner_v2.py:52-58, examples/basic_scan.py:19-21


Scanning Lifecycle

Lifecycle Overview

The scanner follows a structured lifecycle from initialization to report generation:

Diagram: WSHawkV2 Scanning Lifecycle

stateDiagram-v2
    [*] --> Initialization
    
    Initialization --> Connection: run_heuristic_scan()
    Connection --> Learning: connect() succeeds
    Connection --> [*]: Connection failed
    
    Learning --> VulnerabilityTesting: learning_phase() completes
    
    state VulnerabilityTesting {
        [*] --> SQLInjection
        SQLInjection --> XSS
        XSS --> CommandInjection
        CommandInjection --> PathTraversal
        PathTraversal --> XXE
        XXE --> NoSQLInjection
        NoSQLInjection --> SSRF
        SSRF --> [*]
    }
    
    VulnerabilityTesting --> SessionTesting: Connection closed
    SessionTesting --> Cleanup: SessionHijackingTester completes
    
    Cleanup --> Reporting: Resources released
    Reporting --> [*]: HTML report saved
    
    note right of Learning
        5 second observation period
        Collect sample messages
        Fingerprint server
        Detect message format
    end note
    
    note right of VulnerabilityTesting
        Each test uses rate limiting
        Payloads injected intelligently
        Responses verified with heuristics
    end note
    
    note right of Cleanup
        Close headless browser
        Stop OAST provider
        Calculate statistics
    end note

Sources: wshawk/scanner_v2.py:542-677

Lifecycle Methods

| Method | Lifecycle Stage | Lines | Description | |--------|----------------|-------|-------------| | connect() | Connection | 77-85 | Establishes WebSocket connection, updates state machine | | learning_phase() | Learning | 87-141 | Observes traffic for 5 seconds, analyzes message patterns | | test_*_v2() | Testing | Multiple | Individual vulnerability test methods (SQL, XSS, etc.) | | run_heuristic_scan() | Orchestration | 542-677 | Main entry point, coordinates entire lifecycle |

Sources: wshawk/scanner_v2.py:77-677


Learning Phase

Purpose

The learning phase is a critical pre-attack stage where the scanner observes legitimate WebSocket traffic to understand the application's protocol structure. This intelligence enables smart payload injection rather than blind fuzzing.

Diagram: Learning Phase Data Flow

flowchart LR
    Start["learning_phase()<br/>(scanner_v2.py:87)"]
    
    Observe["Observe Traffic<br/>5 second window<br/>(scanner_v2.py:98-114)"]
    
    Collect["Collect Samples<br/>samples list<br/>(scanner_v2.py:102-103)"]
    
    subgraph "Analysis"
        MA["MessageAnalyzer<br/>learn_from_messages()<br/>(scanner_v2.py:121)"]
        SF["ServerFingerprinter<br/>add_response() + fingerprint()<br/>(scanner_v2.py:106, 132)"]
    end
    
    Results["Learning Results<br/>• Message format<br/>• Injectable fields<br/>• Server stack<br/>(scanner_v2.py:124-136)"]
    
    Flag["learning_complete = True<br/>(scanner_v2.py:138)"]
    
    Start --> Observe
    Observe --> Collect
    Collect --> MA
    Collect --> SF
    MA --> Results
    SF --> Results
    Results --> Flag

Sources: wshawk/scanner_v2.py:87-141

Learning Process

The learning_phase() method performs the following steps:

  1. Traffic Observation (scanner_v2.py:98-114):

    • Listens for incoming messages for specified duration (default 5 seconds)
    • Uses asyncio.wait_for() with 1-second timeout to handle idle connections
    • Collects messages in samples list
    • Displays first 3 sample messages for user feedback
  2. Message Analysis (scanner_v2.py:121-129):

    • Passes all samples to MessageAnalyzer.learn_from_messages()
    • Detects message format (JSON, XML, or Binary)
    • Identifies injectable fields (keys in JSON, elements in XML)
    • Stores format information for later payload injection
  3. Server Fingerprinting (scanner_v2.py:106, 132-136):

    • Feeds each message to ServerFingerprinter.add_response()
    • Analyzes patterns to identify backend technology
    • Extracts language, framework, and database information
    • Logs detected stack for user awareness
  4. State Update (scanner_v2.py:138-141):

    • Sets learning_complete = True if samples collected
    • Falls back to basic payload injection if no messages received

Fallback Behavior

If no messages are received during the learning phase:

else:
    Logger.warning("No messages received during learning phase")
    Logger.info("Will use basic payload injection")

The scanner continues with basic string payload injection instead of intelligent field-level injection.

Sources: wshawk/scanner_v2.py:139-141


Test Orchestration

Main Orchestration Method

The run_heuristic_scan() method is the primary entry point for executing a complete security scan. It orchestrates all phases of the scanning lifecycle.

Diagram: run_heuristic_scan() Execution Flow

flowchart TD
    Start["run_heuristic_scan()<br/>(scanner_v2.py:542)"]
    
    Init["Initialize<br/>• start_time<br/>• Logger.banner()"]
    
    Connect["await connect()<br/>(scanner_v2.py:553)"]
    
    CheckConn{"Connection<br/>successful?"}
    
    Learn["await learning_phase()<br/>5 second duration<br/>(scanner_v2.py:561)"]
    
    subgraph "Sequential Vulnerability Tests"
        SQL["test_sql_injection_v2()"]
        XSS["test_xss_v2()"]
        CMD["test_command_injection_v2()"]
        Path["test_path_traversal_v2()"]
        XXE["test_xxe_v2()"]
        NoSQL["test_nosql_injection_v2()"]
        SSRF["test_ssrf_v2()"]
    end
    
    Close["await ws.close()"]
    
    Session["SessionHijackingTester<br/>run_all_tests()<br/>(scanner_v2.py:594-613)"]
    
    Cleanup["Cleanup<br/>• headless_verifier.stop()<br/>• oast_provider.stop()"]
    
    Stats["Calculate Statistics<br/>• duration<br/>• messages sent/received<br/>• vulnerability count"]
    
    Report["Generate HTML Report<br/>EnhancedHTMLReporter<br/>(scanner_v2.py:659-670)"]
    
    Return["Return vulnerabilities list"]
    
    Start --> Init
    Init --> Connect
    Connect --> CheckConn
    CheckConn -->|Yes| Learn
    CheckConn -->|No| Return
    Learn --> SQL
    SQL --> XSS
    XSS --> CMD
    CMD --> Path
    Path --> XXE
    XXE --> NoSQL
    NoSQL --> SSRF
    SSRF --> Close
    Close --> Session
    Session --> Cleanup
    Cleanup --> Stats
    Stats --> Report
    Report --> Return

Sources: wshawk/scanner_v2.py:542-677

Test Execution Sequence

Tests are executed sequentially in the following order:

| Order | Test Method | Target Vulnerability | Lines | |-------|-------------|---------------------|-------| | 1 | test_sql_injection_v2() | SQL Injection | 143-210 | | 2 | test_xss_v2() | Cross-Site Scripting | 212-290 | | 3 | test_command_injection_v2() | Command Injection / RCE | 292-356 | | 4 | test_path_traversal_v2() | Path Traversal / LFI | 358-397 | | 5 | test_xxe_v2() | XML External Entity | 399-453 | | 6 | test_nosql_injection_v2() | NoSQL Injection | 455-493 | | 7 | test_ssrf_v2() | Server-Side Request Forgery | 495-540 | | 8 | Session Tests (separate connection) | Session Security Issues | 594-613 |

Sources: wshawk/scanner_v2.py:565-584, 590-613

Vulnerability Recording

Each test method follows a consistent pattern for recording vulnerabilities:

self.vulnerabilities.append({
    'type': 'SQL Injection',
    'severity': confidence.value,
    'confidence': confidence.value,
    'description': description,
    'payload': payload,
    'response_snippet': response[:200],
    'recommendation': 'Use parameterized queries'
})

The vulnerabilities list is then used for:

  • Console output during scan
  • HTML report generation
  • Statistics calculation
  • Return value for programmatic access

Sources: wshawk/scanner_v2.py:190-198


Test Method Pattern

Common Structure

All test methods (test_*_v2) follow a consistent pattern:

Diagram: Test Method Pattern

flowchart TD
    Start["test_*_v2(ws)"]
    
    Log["Logger.info('Testing...')"]
    
    Init["Initialize<br/>• results = []<br/>• Load payloads"]
    
    Fingerprint{"Server<br/>fingerprinted?"}
    
    GetSpecific["Get server-specific payloads<br/>fingerprinter.get_recommended_payloads()"]
    
    GetBase["Get base message<br/>sample_messages[0] or default"]
    
    Loop["For each payload"]
    
    CheckFormat{"learning_complete<br/>AND<br/>format == JSON?"}
    
    InjectSmart["inject_payload_into_message()<br/>Multiple injection points"]
    
    InjectBasic["Use raw payload"]
    
    Send["await ws.send(msg)"]
    
    Recv["await ws.recv()<br/>with timeout"]
    
    Verify["VulnerabilityVerifier<br/>verify_*() method"]
    
    CheckVuln{"is_vuln AND<br/>confidence != LOW?"}
    
    BrowserCheck{"use_headless_browser<br/>AND<br/>HIGH confidence?"}
    
    HeadlessVerify["HeadlessBrowserXSSVerifier<br/>verify_xss_execution()"]
    
    Record["Append to vulnerabilities list<br/>Logger.vuln()"]
    
    RateLimit["await asyncio.sleep(0.05)"]
    
    Return["return results"]
    
    Start --> Log
    Log --> Init
    Init --> Fingerprint
    Fingerprint -->|Yes| GetSpecific
    Fingerprint -->|No| GetBase
    GetSpecific --> GetBase
    GetBase --> Loop
    Loop --> CheckFormat
    CheckFormat -->|Yes| InjectSmart
    CheckFormat -->|No| InjectBasic
    InjectSmart --> Send
    InjectBasic --> Send
    Send --> Recv
    Recv --> Verify
    Verify --> CheckVuln
    CheckVuln -->|Yes| BrowserCheck
    CheckVuln -->|No| RateLimit
    BrowserCheck -->|Yes for XSS| HeadlessVerify
    BrowserCheck -->|No| Record
    HeadlessVerify --> Record
    Record --> RateLimit
    RateLimit --> Loop
    Loop --> Return

Sources: wshawk/scanner_v2.py:143-290 (SQL and XSS examples)

Example: SQL Injection Test

The SQL injection test demonstrates the full pattern:

1. Initialization (scanner_v2.py:147-150):

results = []
payloads = WSPayloads.get_sql_injection()[:100]  # Limit for performance

2. Server-Specific Payloads (scanner_v2.py:152-158):

fingerprint = self.fingerprinter.fingerprint()
if fingerprint.database:
    recommended = self.fingerprinter.get_recommended_payloads(fingerprint)
    if recommended.get('sql'):
        payloads = recommended['sql'] + payloads[:50]

3. Intelligent Injection (scanner_v2.py:166-171):

if self.learning_complete and self.message_analyzer.detected_format == MessageFormat.JSON:
    injected_messages = self.message_analyzer.inject_payload_into_message(
        base_message, payload
    )
else:
    injected_messages = [payload]

4. Verification with Confidence (scanner_v2.py:182-184):

is_vuln, confidence, description = self.verifier.verify_sql_injection(
    response, payload
)

5. Recording Vulnerabilities (scanner_v2.py:186-198):

if is_vuln and confidence != ConfidenceLevel.LOW:
    Logger.vuln(f"SQL Injection [{confidence.value}]: {description}")
    self.vulnerabilities.append({...})

Sources: wshawk/scanner_v2.py:143-210

XSS-Specific: Headless Browser Verification

The XSS test includes optional real browser verification for HIGH confidence findings:

if confidence == ConfidenceLevel.HIGH and self.use_headless_browser:
    if not self.headless_verifier:
        self.headless_verifier = HeadlessBrowserXSSVerifier()
        await self.headless_verifier.start()
    
    is_executed, evidence = await self.headless_verifier.verify_xss_execution(
        response, payload
    )
    
    if is_executed:
        browser_verified = True
        confidence = ConfidenceLevel.CRITICAL

This upgrades confidence from HIGH to CRITICAL if the payload executes in a real browser. See Playwright XSS Verification for details.

Sources: wshawk/scanner_v2.py:248-262

XXE-Specific: OAST Integration

The XXE test uses Out-of-Band Application Security Testing for blind detection:

if self.use_oast and not self.oast_provider:
    self.oast_provider = OASTProvider(use_interactsh=False, custom_server="localhost:8888")
    await self.oast_provider.start()

if self.use_oast and self.oast_provider:
    oast_payload = self.oast_provider.generate_payload('xxe', f'test{len(results)}')
    msg = json.dumps({"action": "parse_xml", "xml": oast_payload})

See OAST Blind Vulnerability Detection for details.

Sources: wshawk/scanner_v2.py:407-423


Cleanup and Reporting

Resource Cleanup

After all tests complete, the scanner performs cleanup of external resources:

Diagram: Cleanup Sequence

sequenceDiagram
    participant Scanner as "WSHawkV2"
    participant HV as "headless_verifier"
    participant OAST as "oast_provider"
    participant Rep as "EnhancedHTMLReporter"
    participant FS as "File System"
    
    Scanner->>Scanner: await ws.close()
    
    Scanner->>Scanner: Check if headless_verifier exists
    
    alt Headless browser was used
        Scanner->>HV: await headless_verifier.stop()
        HV-->>Scanner: Browser closed
    end
    
    Scanner->>Scanner: Check if oast_provider exists
    
    alt OAST was used
        Scanner->>OAST: await oast_provider.stop()
        OAST-->>Scanner: Provider stopped
    end
    
    Scanner->>Scanner: Calculate statistics<br/>duration, message counts
    
    Scanner->>Scanner: Get fingerprint_info
    
    Scanner->>Rep: generate_report(vulnerabilities, scan_info, fingerprint_info)
    Rep-->>Scanner: HTML string
    
    Scanner->>FS: Write report file<br/>wshawk_report_TIMESTAMP.html
    
    Scanner->>Scanner: Log rate limiter stats
    
    Scanner->>Scanner: return vulnerabilities

Sources: wshawk/scanner_v2.py:615-677

Statistics Collection

The scanner collects comprehensive statistics for the final report:

self.end_time = datetime.now()
duration = (self.end_time - self.start_time).total_seconds()

scan_info = {
    'target': self.url,
    'duration': duration,
    'messages_sent': self.messages_sent,
    'messages_received': self.messages_received
}

Sources: wshawk/scanner_v2.py:631-655

Confidence Breakdown

Vulnerabilities are categorized by confidence level:

if self.vulnerabilities:
    Logger.info("Confidence breakdown:")
    for level in ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW']:
        count = sum(1 for v in self.vulnerabilities if v['confidence'] == level)
        if count > 0:
            print(f"  {level}: {count}")

Sources: wshawk/scanner_v2.py:640-646

HTML Report Generation

The scanner generates an enhanced HTML report containing:

  • Vulnerability summary with CVSS scores
  • Detailed findings for each vulnerability
  • Server fingerprint information
  • Message statistics
  • Recommendations
fingerprint_info = self.fingerprinter.get_info()

report_html = self.reporter.generate_report(
    self.vulnerabilities,
    scan_info,
    fingerprint_info
)

report_filename = f"wshawk_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.html"
with open(report_filename, 'w') as f:
    f.write(report_html)

See Report Format and Output for details on the report structure.

Sources: wshawk/scanner_v2.py:649-670

Rate Limiter Statistics

Final statistics from the rate limiter are logged:

rate_stats = self.rate_limiter.get_stats()
Logger.info(f"Rate limiter: {rate_stats['total_requests']} requests, {rate_stats['total_waits']} waits")
Logger.info(f"  Current rate: {rate_stats['current_rate']}, Adaptive adjustments: {rate_stats['adaptive_adjustments']}")

See Rate Limiting and Session State for details on rate limiting.

Sources: wshawk/scanner_v2.py:673-675


Usage Patterns

Basic Programmatic Usage

The simplest way to use the scanner programmatically:

import asyncio
from wshawk.scanner_v2 import WSHawkV2

async def scan_target():
    scanner = WSHawkV2("ws://example.com/ws", max_rps=10)
    
    # Optional: disable advanced features for faster scan
    scanner.use_headless_browser = False
    scanner.use_oast = False
    
    # Run scan
    vulnerabilities = await scanner.run_heuristic_scan()
    
    # Access results
    for vuln in vulnerabilities:
        print(f"{vuln['type']}: {vuln['description']}")

asyncio.run(scan_target())

Sources: examples/basic_scan.py:12-40

With Custom Headers

Adding authentication or custom headers:

headers = {
    'Authorization': 'Bearer token123',
    'X-Custom-Header': 'value'
}

scanner = WSHawkV2("ws://example.com/ws", headers=headers)

Sources: wshawk/scanner_v2.py:33-37

With Authentication Sequence

Loading authentication from YAML file:

scanner = WSHawkV2(
    "ws://example.com/ws",
    auth_sequence="auth_config.yaml"
)

The YAML file is loaded by the SessionStateMachine. See Configuration and Authentication for details.

Sources: wshawk/scanner_v2.py:61-62

Accessing Individual Test Methods

Running specific tests instead of full scan:

scanner = WSHawkV2("ws://example.com/ws")

ws = await scanner.connect()
if ws:
    await scanner.learning_phase(ws, duration=5)
    
    # Run only SQL injection tests
    sql_results = await scanner.test_sql_injection_v2(ws)
    
    # Run only XSS tests
    xss_results = await scanner.test_xss_v2(ws)
    
    await ws.close()

Sources: wshawk/scanner_v2.py:143-290

Enabling/Disabling Verification

Controlling optional verification features:

scanner = WSHawkV2("ws://example.com/ws")

# Enable headless browser for XSS verification
scanner.use_headless_browser = True

# Disable OAST for faster scan (no blind XXE/SSRF detection)
scanner.use_oast = False

await scanner.run_heuristic_scan()

Sources: wshawk/scanner_v2.py:52-58, examples/basic_scan.py:19-21

Rate Limiting Configuration

Adjusting scan speed:

# Slow scan (5 requests/second)
scanner = WSHawkV2("ws://example.com/ws", max_rps=5)

# Fast scan (20 requests/second)
scanner = WSHawkV2("ws://example.com/ws", max_rps=20)

# The rate limiter automatically adjusts if server shows signs of overload

The TokenBucketRateLimiter includes adaptive rate control. See Rate Limiting and Session State for details.

Sources: wshawk/scanner_v2.py:35, 45-49


Integration with CLI

The scanner is used by all CLI entrypoints:

| CLI Command | Usage | Integration Point | |-------------|-------|------------------| | wshawk | Quick scan | Creates WSHawkV2 instance, calls run_heuristic_scan() | | wshawk-interactive | Interactive mode | User selects tests, calls specific test_*_v2() methods | | wshawk-advanced | Advanced features | Enables use_headless_browser and use_oast |

See CLI Command Reference for details on CLI usage.

Sources: wshawk/init.py:5-6


Error Handling

The scanner implements defensive error handling throughout:

Connection Errors

try:
    ws = await websockets.connect(self.url, additional_headers=self.headers)
    self.state_machine._update_state('connected')
    return ws
except Exception as e:
    Logger.error(f"Connection failed: {e}")
    return None

Sources: wshawk/scanner_v2.py:78-85

Test Method Errors

Each test method wraps payload execution in try-except:

for payload in payloads:
    try:
        # ... send and receive ...
    except Exception as e:
        Logger.error(f"SQL test error: {e}")
        continue  # Move to next payload

This ensures one failing payload doesn't crash the entire scan.

Sources: wshawk/scanner_v2.py:206-208

Cleanup Errors

Cleanup operations are individually wrapped:

if self.headless_verifier:
    try:
        await self.headless_verifier.stop()
        Logger.info("Headless browser stopped")
    except Exception as e:
        Logger.error(f"Browser cleanup error: {e}")

Sources: wshawk/scanner_v2.py:616-621


Performance Considerations

Rate Limiting

The scanner uses TokenBucketRateLimiter to:

  • Prevent server overload
  • Avoid detection by rate-based WAFs
  • Ensure scan completes without connection drops

Sources: wshawk/scanner_v2.py:45-49

Payload Limiting

Test methods limit payload counts for performance:

payloads = WSPayloads.get_sql_injection()[:100]  # Use first 100 only

This balances coverage with scan duration.

Sources: wshawk/scanner_v2.py:150

Async Operations

All I/O operations use async/await:

  • WebSocket send/receive
  • Headless browser operations
  • OAST polling

This enables efficient concurrent operations.

Sources: wshawk/scanner_v2.py:1-677

Timeout Management

All receive operations include timeouts:

response = await asyncio.wait_for(ws.recv(), timeout=2.0)

This prevents indefinite hangs on unresponsive servers.

Sources: wshawk/scanner_v2.py:178