Browser Validation

Article 4: Playwright-Assisted DOM XSS Evidence Collection

Source File: wshawk/headless_xss_verifier.py
Relevant Class: HeadlessBrowserXSSVerifier

4.1 The False Positive Dilemma

Automated scanners detect Cross-Site Scripting (XSS) by sending a payload like <script>alert(1)</script> and checking if it reflects in the HTTP response.

However, modern frontend frameworks (React, Vue, Angular) often sanitize outputs or bind data safely (e.g., using element.innerText rather than element.innerHTML). In these cases, the payload reflects exactly as sent in the network traffic, but it is inert in the browser DOM. Flagging this as a vulnerability creates massive volumes of false positives.

4.2 Sandboxed DOM Verification

To collect stronger XSS execution evidence and reduce reflection-only false positives, WSHawk can run a headless Chromium browser through the asynchronous playwright library.

When the scanner detects a reflected payload in the WebSocket stream, it invokes HeadlessBrowserXSSVerifier.

  1. Context Creation: It spins up an isolated Chromium page in the background.
  2. Beacon Injection: It overrides the native browser alert function to trap execution without halting the automated test:
    window.xssExecuted = false;
    const originalAlert = window.alert;
    window.alert = function(msg) {
        window.xssExecuted = true;
        originalAlert(msg);
    };
  3. DOM Evaluation: It renders the suspected HTML reflection inside the Chromium context. If the payload executes, the overridden alert fires, and the window.xssExecuted beacon evaluates to true.
  4. Mutation Tracking: Beyond simple alerts, the verifier also queries the DOM for injected <script> tags or inline event handlers (onerror, onmouseover) injected by the payload, handling complex DOM-based execution flows.

If the beacon fires or a relevant DOM mutation is observed, WSHawk records browser-assisted evidence. If the payload remains inert, the reflection is not treated as execution proof. This is a useful confirmation layer, not a universal guarantee: application state, Content Security Policy, timing, and the reproduced DOM context can still affect the result.