Runtime JavaScript security analysis. Launches Chrome with CDP, captures every script as it executes, and runs CodeQL to find vulnerabilities with full dataflow traces.
Unlike static scanners that analyze source files on disk, this tool captures JavaScript as the browser sees it — including dynamically fetched scripts, inline scripts, eval'd code, and scripts injected at runtime. Each execution context (page, iframe) gets its own CodeQL database so cross-file analysis is accurate and findings don't cross-contaminate between unrelated pages.
pip install PySide6 websocket-client
# GUI — launches Chrome, analyzes as you browse
python main.py
# CLI — analyze specific URLs
python main.py https://example.com
# Spider — crawl and analyze an entire site
python main.py --spider https://example.comCodeQL is downloaded automatically on first run (~620MB).
- Chrome launches with a persistent profile and CDP enabled on port 9222
- CDP captures all JavaScript via
Debugger.scriptParsed— external files, inline scripts,eval'd code, dynamically imported modules - Execution contexts are tracked via
Runtime.executionContextCreated— each page and each cross-origin iframe is isolated - Debounce fires 3 seconds after the last script arrives in a context
- CodeQL daemon (parallel workers) creates a database per context, runs the full
javascript-security-extendedquery suite - Findings with full traces are persisted to
findings.json, source files tosources/ - System notification fires when new findings are detected
GUI and CLI share the same Chrome instance, the same findings store, and the same persistent profile. Run the CLI while the GUI is open — findings appear in both.
python main.py [OPTIONS] URL [URL...]
| Flag | Default | Description |
|---|---|---|
--spider |
off | Crawl links from each URL using the live DOM |
--depth N |
3 | Spider crawl depth |
--max-pages N |
50 | Spider max pages |
--scope |
same-origin |
same-origin, same-domain, prefix, regex |
--scope-pattern |
Pattern for prefix/regex scope |
|
--wait N |
5 | Seconds to wait per page for scripts |
--output FILE |
Write merged SARIF to file | |
--json |
Print findings as JSON | |
--clear |
Clear persisted findings before running | |
--port N |
9222 | CDP port |
--chrome PATH |
auto | Chrome executable path |
--codeql PATH |
auto | CodeQL CLI path |
# Analyze a single page
python main.py https://example.com
# Spider a site
python main.py --spider --max-pages 30 https://example.com
# Output SARIF for CI
python main.py --output results.sarif https://example.com
# Clear old findings and rescan
python main.py --clear --spider https://example.compython main.pyOn startup the GUI automatically launches Chrome (or connects to an existing instance on port 9222), starts capturing scripts, and loads any persisted findings from previous sessions.
Toolbar: Spider | Clear Findings | Settings
Panels:
- Findings (left) — sortable, filterable table: severity, rule, message, script URL, page context, file, line
- Trace (top right) — dataflow trace from source to sink, click a step to navigate
- Source (bottom right) — full JavaScript source with syntax highlighting and line numbers
Browse any page in Chrome — scripts are captured and analyzed automatically. Findings appear as they're found with a system notification.
Everything is shared between GUI and CLI:
| What | Where | Shared how |
|---|---|---|
| Chrome instance | Port 9222 | Both connect to the same CDP port |
| Chrome profile | chrome-profile/ |
Persistent — cookies, logins, history survive restarts |
| Findings | findings.json |
GUI watches for changes, updates live |
| Source files | sources/{hash}/ |
Full JS files kept for any context with findings |
| CodeQL | codeql/ |
Auto-downloaded bundle, shared |
Each CodeQL database contains only the scripts from one execution context:
- Same page:
app.jsandlib.jsloaded by the same page share awindow— analyzed together - Cross-origin iframe:
https://ads.netinhttps://example.comgets a separate database — no false positives - Navigation: page A → page B creates new contexts — scripts never mix
The isolation key is Chrome's context.uniqueId from Runtime.executionContextCreated.
| Detail | Value |
|---|---|
| Query suite | javascript-security-extended.qls — full suite, no exclusions |
| Workers | Parallel (auto-scaled to CPU cores) |
| Per worker | Threads and RAM divided evenly across workers |
| Cache | Compiled queries reused across all databases |
| Sources | Full JS files persisted by content hash when findings exist |
The full suite covers XSS, code injection, open redirects, request forgery, postMessage issues, prototype pollution, insecure crypto, SQL injection, command injection, path traversal, cookie issues, hardcoded credentials, and more. Queries that don't match browser code produce zero results with negligible overhead.
The spider drives Chrome through the live DOM using Runtime.evaluate to extract links from rendered <a>, <area>, and <form> elements. It handles SPAs, JS-rendered navigation, and dynamically injected links.
Each page visited triggers the capture → debounce → analysis pipeline automatically.
main.py Entry point — routes to GUI or CLI
cli.py CLI with spider and CodeQL daemon
app/
cdp_client.py CDP WebSocket client (context tracking, auto-attach iframes)
chrome_launcher.py Chrome lifecycle (launch or reuse existing, persistent profile)
spider.py BFS crawler via live DOM
codeql_daemon.py Parallel analysis daemon (thread pool)
codeql_runner.py CodeQL subprocess wrapper
codeql_setup.py Auto-downloads CodeQL bundle
config.py Query suite config, path detection
findings_store.py Persistent findings (JSON, dedup, SARIF/JSON export)
sarif_parser.py SARIF v2.1.0 parser
script_store.py Saves captured JS to disk, reverse lookup
workers.py Qt thread workers (capture, spider, setup)
cleanup.py Startup cleanup of stale temp dirs
gui/
main_window.py Main window, auto-analysis, context lifecycle
toolbar.py Spider / Clear / Settings
findings_panel.py Findings table
trace_panel.py Dataflow trace tree
source_panel.py Code editor with JS highlighting
- Python 3.11+
- PySide6
- websocket-client
- Chrome (detected automatically)
- CodeQL (downloaded automatically)
