Overview
Single-page applications built with frameworks like React, Angular, or Vue render content dynamically in the browser. Traditional crawlers that parse raw HTML will miss most endpoints because routes, API calls, and UI interactions are driven by JavaScript. Vigolium addresses this with browser-based spidering that executes JavaScript and captures network traffic as it navigates the application.How Vigolium Handles SPAs
Vigolium’s browser-based spidering engine (Spitolas) uses Chromium via the Chrome DevTools Protocol (CDP) to:- Render JavaScript: Pages are fully rendered in a headless browser, allowing Vigolium to discover routes that only exist after JS execution.
- Capture network traffic: All HTTP requests made by the application (XHR, fetch, WebSocket upgrades) are intercepted via CDP and fed into the scanner as inputs.
- Interact with the DOM: The spider clicks buttons, fills forms, and triggers UI events to discover endpoints behind user interactions.
- Exercise JS-driven POST forms: Beyond filling forms, the crawl now triggers same-origin POST-form submit handlers — surfacing the JS-driven POST endpoints (a common home for XXE and body/cookie SQLi) that never appear in the raw HTML. Destructive submits (delete/logout,
_method-override forms) are skipped, and the pass is disabled by--no-forms. - Confirm DOM-based XSS in the browser: On the reflected client routes it visited, the crawl runs a browser-confirmed DOM-XSS probe — an execution canary must actually fire in the browser before it reports the finding “DOM-based XSS (Browser-Confirmed)” (
spider-dom-xss). It is bounded so it corroborates real DOM-XSS without dominating the crawl. - Extract client-side routes: SPA router configurations and navigation links are identified even when they do not result in full page loads.
Running a SPA Scan
The defaultbalanced strategy includes browser spidering automatically:
deep strategy which increases spidering depth and interaction aggressiveness:
--only:
Browser Requirements
Vigolium requires a Chromium-based browser for spidering. On first use, it automatically downloads a compatible Chromium binary. No manual installation is needed in most cases. For environments where auto-download is not possible (air-gapped systems, containers), pre-install Chromium and point Vigolium to it via thespidering.browser_path config option.
Launch tries candidates in priority order and falls through on failure. Instead of resolving a single browser binary and aborting the scan if it crashes, spidering enumerates candidates in priority order — configured
spidering.browser_path → the embedded engine binary → system Google Chrome → system Chromium → Chrome for Testing (cached, then downloaded) → rod auto-download — and moves to the next whenever one fails the launch/DevTools handshake. So a crash-on-startup distro Chromium auto-recovers to a working browser (in practice Chrome for Testing) rather than aborting; only when every candidate fails does launch return an aggregated error.Tuning Spidering
Spidering behavior is configurable viavigolium-configs.yaml or CLI flags:
max_pages and max_depth to ensure full coverage. For quick assessments, reduce them to keep scan times short. tabs is usually the cheaper win: it raises throughput without widening the crawl.
Two v0.5.3 additions matter specifically for SPAs:
- Client routes found in JavaScript seed the crawl (
route_seeds). The router table a SPA ships in its bundle names views the crawler would otherwise only reach by guessing the right click path. - The crawler clicks into shadow DOM and web components, so an app built on a custom-element design system is no longer a blank page to it.
What the crawler will and will not do
The browser sandbox is on by default as of v0.5.2;
--browser-insecure restores the old posture for a target that genuinely needs it. Crawl graphs are written as crawl-graph-<host>-<scan>-<seq>.json, redacted and owner-only — widen any glob written against the old name. Redaction matters because a crawl graph records the form values used, including whatever the fill context put in a password field; spidering.graph_include_values turns it off.Common Issues
Browser Not Found
If you see an error about a missing browser executable:- Ensure you have internet access for the auto-download, or set
spidering.browser_pathto a local Chromium installation. - In Docker containers, use the embedded build or install Chromium in the image.
Timeouts
SPAs with heavy client-side rendering or slow APIs may cause page load timeouts:- Increase the page timeout via
spidering.page_timeoutin the config. - Ensure the target application is responsive and accessible from the scanner host.
Headless Detection
Some applications block headless browsers. Vigolium applies common evasion techniques by default, but if the application still blocks requests:- Try setting
browser.headless: falsefor headed mode (requires a display server or Xvfb). - Use a custom user agent via
browser.user_agentin the config. - Consider feeding pre-recorded traffic (HAR, Burp XML) as input instead of relying on live spidering.
