WSHawkV2 Scanner Engine
WSHawkV2 Scanner Engine
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
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:
-
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
sampleslist - Displays first 3 sample messages for user feedback
-
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
- Passes all samples to
-
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
- Feeds each message to
-
State Update (scanner_v2.py:138-141):
- Sets
learning_complete = Trueif samples collected - Falls back to basic payload injection if no messages received
- Sets
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