A Go-native, CLI web-application security scanner that combines 113 context-aware native detectors, 8 third-party tool integrations (SQLMap, Dalfox, Commix, Ghauri, Nikto, WPScan, Nuclei, Tplmap) with smart auto-dispatch, a Nuclei-compatible template engine with full protocol parity, a headless-browser pool for DOM- and origin-aware checks, and a native SAST engine (secret scanning, SCA, config audits). Findings are mapped to OWASP WSTG, Top 10 (2025), API Security Top 10, and compliance frameworks (PCI DSS, HIPAA, SOC 2).
vigil scan https://target.com works with zero flags — smart
defaults auto-detect the target's tech stack, API spec, SPA framework,
and choose the right detectors and tools. Rich inline TUI with colored
severity badges, progress bars, and evidence per finding in interactive
terminals; plain headless output for CI/CD and automation (--headless).
vigil focuses on the categories Nuclei templates structurally cannot reach — stateful business-logic bugs, two-identity IDOR/BOLA, race conditions over raw HTTP/2 frames, postMessage origin validation, authenticated cache deception, and more — while reusing the upstream Nuclei community template store for everything Nuclei already does well.
Status: pre-1.0. Detector defaults and the CLI surface may still shift between minor versions — pin a tag or commit if you depend on exact behavior.
- Multi-technique SQL injection — error-based, boolean-blind, UNION-based (binary-search column detection, multi-DB fingerprint), response-differential (catches custom JSON error wrappers), time-based blind, error-differential (status-code change on metacharacter), and CTE bypass (WITH clause evades WAFs that block UNION SELECT — MySQL 8+, PostgreSQL, MSSQL, SQLite, Oracle). Location-aware: works on query, JSON body, XML body, path, header, and cookie params. Length-ratio similarity catches table-heavy differentials that set-based Jaccard misses.
- OpenAPI-first API scanning — YAML + JSON spec parsing, requestBody property extraction, sibling body-param injection (sends all fields so multi-field endpoints reach the SQL layer), per-endpoint method + URL routing.
- Command injection — output-pattern detection (Linux + Windows), time-based blind, and error-differential (status-code change on command separators
;,|,`). Catches blind CMDI where output is suppressed. - Code injection detection — raw eval()/exec() detection via arithmetic probes (catches Python eval, Node vm, Ruby eval) alongside template-engine SSTI.
- XXE with body replacement — for XML-accepting endpoints, sends the full DOCTYPE + entity declaration as the request body with the correct element name from the API schema.
- XSS with executable-context verification — reflected XSS payloads are checked for unencoded dangerous characters (
<,>,",') at the reflection point. Filters out HTML-encoded reflections that appear reflected but are not executable. - Link-crawling discovery — BFS crawl of same-origin pages (default 30), runs all 17 discoverers on each page. Finds form params, hidden inputs, and endpoints on subpages that a root-only fetch misses. Form
actionattributes are resolved to correct endpoint URLs. Query params from crawled link URLs are extracted at zero HTTP cost. - JS endpoint extraction — parses
fetch(),axios.post(),$.ajax(), and$.post()patterns in inline and external JavaScript to discover POST body params with JSON content type. Catches SPA/AJAX endpoints invisible to HTML-only discovery. - Reflected-parameter brute-forcer — probes ~65 common param names via GET, POST form-urlencoded, and POST JSON on the root page. Detects hidden params via value reflection or body-size change.
- Content-type negotiation — during param classification, if form-urlencoded POST returns 500, automatically retries with JSON. Tags the param so all subsequent probes use the correct encoding.
- Type-aware sibling defaults — multi-field forms send realistic values for sibling params (numeric IDs, email format, password format, booleans) instead of a generic "test" that fails validation.
- Body-first parameter priority — body params with semantic names (username, password, email, id) are tested first; single-letter JS query noise tested last. Ensures the most injectable params get tested even under time constraints.
- Parallel detector pipeline — configurable param concurrency (default 5) and per-param detector concurrency (default 3). Param cap (default 200) prevents multi-hour scans on large apps.
- Smart tool dispatch — native detectors find injection points in seconds, then automatically launch focused tool runs (sqlmap with
--dbmshint, dalfox with--paramtargeting) for deep exploitation. No user interaction needed. Autonomous mode runs core tools (sqlmap, dalfox, nikto, nuclei) at full strength in parallel. - Stored XSS — full inject → crawl → match → confirm workflow
- Native SAST —
vigil sast ./srcfor secret scanning, dependency CVEs (OSV.dev), and config security - Form auto-submission — smart crawl discovers pages behind form gates (
--submit-forms) - Auto template discovery — loads
~/nuclei-templates+~/.local/share/vigil/custom-nuclei-templates/templatesby default. Override with--templatesorVIGIL_TEMPLATESenv. - Nuclei template parity — 20 headless actions, file / workflow / code templates, unsafe-raw (smuggling), pipeline (HTTP/2 desync), interactsh OOB polling
- AI finding triage — Haruspex adjudication scores each finding's "real vs noise" probability
- WAF bypass payloads — per-class evasion variants: SQLi (inline comments, hex encoding, CTE WITH clause, scientific notation, whitespace alternatives, double URL encoding), SSRF (octal/hex/decimal/IPv6 IP encoding, DNS rebinding, Unicode IDNA), LFI (null byte, UTF-8 overlong, backslash), XSS (unicode normalization NFKC, SVG onload, event handler injection). Long-payload padding pushes injection past WAF body inspection limits (8KB AWS WAF, 128KB Cloudflare).
- Risk-gated payloads — destructive SQL payloads (
DROP TABLE,xp_cmdshell) require--risk 3 - Incremental results — findings flush to disk after each scan phase, so early results survive if a later phase times out
- Web console, full API & MCP —
vigil webopens a multi-page console (dashboard, targets, scans, live triage, reports, compliance, settings) backed by an authenticated JSON API that exposes every feature;vigil mcpserves the same operations to AI agents over the Model Context Protocol
- Why vigil
- Quickstart
- Installation
- Usage
- Detection coverage (DAST)
- Static analysis (SAST)
- Web dashboard & API
- MCP server
- Headless / two-identity probes
- External tool integrations
- CI/CD integration
- How vigil compares
- Architecture
- Project layout
- Development
- Contributing
- Security policy
- License
A scanner is only as good as the categories it can express. Nuclei is excellent at fingerprint / CVE / regex-on-response checks, but it has no JavaScript runtime, no session model, and no way to compare behavior across two authenticated identities. vigil fills exactly that gap:
- Two-identity IDOR / BOLA. Probe the same URL with two different auth states and report when user A's response leaks to user B.
- Race conditions with H/1 last-byte synchronisation and H/2 single-packet bursts (CVE-2023-44487-style raw-frame control).
- Web cache deception with optional unauthenticated replay verification.
- Authenticated postMessage origin probe that dispatches a
synthetic
MessageEventfrom an attacker origin and watches which DOM/storage sinks the page's listeners mutated. - Smuggling, JWT cryptanalysis, OAuth/OIDC, GraphQL introspection, OpenAPI spec runner, second-order injection — all stateful, multi-request flows.
- Location-aware payload dispatch (
SendPayloadAt): JSON body, multipart, XML, path segment, header, and cookie injection points discovered by the auto-discovery pipeline are tested in the right transport, not silently shoved into the query string.
vigil runs Nuclei alongside itself when the binary is on PATH —
you do not have to choose between the two.
# install
go install -v github.com/TyrusRC/vigil/cmd/vigil@latest
# scan — just give it a target, vigil handles the rest
vigil scan https://example.com
# scan a codebase for secrets and vulnerable dependencies
vigil sast ./my-projectgo install -v github.com/TyrusRC/vigil/cmd/vigil@latestgit clone https://github.com/TyrusRC/vigil.git
cd vigil
make build # produces ./bin/vigil
make install # optional: install into $GOBINdocker build -t vigil .
docker run --rm vigil scan https://example.com- Go 1.24+ to build from source.
- (optional) a Chromium-based browser for DOM-aware detectors and
the postMessage probe —
go-rodauto-downloads one on first use, or pass--chrome-pathto use a system binary. - (optional)
nucleiand/orsqlmaponPATHto enable the external-tool wrappers. vigil degrades gracefully when they are missing.
vigil scan https://example.comThat's it. Vigil auto-detects the tech stack, discovers parameters, picks the right detectors, and runs them. No flags needed for a standard scan — the defaults cover OWASP Top 10, API injection, business logic, and more.
Reports auto-save to vigil-report-<timestamp>/ when findings exist.
Real-time findings appear in the terminal as they're discovered.
# multiple targets
vigil scan -l targets.txt
# scan a codebase (SAST)
vigil sast ./src
# CI/CD gate — fail the build on high+ findings
vigil scan "$TARGET" --fail-on high --format sarif --output-dir report
# headless mode for automation (no colors, no progress bar)
vigil scan --headless https://example.comAdvanced flags (authentication, proxy, tuning)
- positional argument:
vigil scan https://example.com - target list file:
vigil scan -l targets.txt - piped from stdin:
cat targets.txt | vigil scan
| Flag | Description |
|---|---|
-H, --header KEY:VAL |
Custom request header (repeatable) |
--cookie STRING |
Cookie: header value |
-A, --user-agent UA |
Custom User-Agent for ALL scanner traffic |
--proxy URL |
Proxy URL (HTTP CONNECT honored — Burp Suite friendly) |
-k, --insecure |
Skip TLS verification (needed when Burp/MitM uses its own CA) |
-d, --data STRING |
POST body (form-urlencoded by default) |
-X, --method METHOD |
HTTP method (default GET) |
--login-url URL |
Login page URL for form-based authentication |
--login-user USER |
Login username |
--login-pass PASS |
Login password (prefer VIGIL_LOGIN_PASS env var) |
--login-headless |
Use headless browser for login (SPAs, JS-rendered forms) |
--login-success STRING |
Marker string in post-login response confirming success |
| Flag | Description | Default |
|---|---|---|
-t, --timeout DURATION |
Total scan timeout | 30m |
-c, --concurrency N |
Concurrent tools | 3 |
--profile NAME |
Scan profile (quick, normal, thorough) |
|
--level 1-5 |
SQLMap-style level | 1 |
--risk 1-3 |
SQLMap-style risk | 1 |
--templates DIR |
Nuclei-style template dir/file; repeatable — pass once per path to load the default store and custom templates together (e.g. --templates ~/nuclei-templates --templates ~/custom-nuclei-templates) |
|
--api-spec URL |
OpenAPI/Swagger JSON; runner exercises every endpoint | |
--stored-xss |
Enable stored XSS detection (auto at --level 3+) |
off |
--submit-forms |
Submit discovered forms during crawl to find gated pages | off |
--format LIST |
Output formats: json, html, markdown, csv, sarif, junit, gitlab (comma-separated) |
json |
--fail-on SEVERITY |
Exit code 2 when findings meet or exceed this severity | |
--fail-on-new |
Gate only on findings absent from --baseline |
off |
--baseline FILE |
Previous scan JSON; diff-only for incremental scanning |
Rank the loaded templates by relevance to the target's detected tech before the run — the "Jev for nuclei" idea. Env-driven, opt-in, two backends:
| Env | Effect |
|---|---|
VIGIL_DECIDE=1 |
Enable the decision engine (deterministic tech-tag ranking, no key). |
AI_GATEWAY_API_KEY |
Use TypeSafe Jev via Vercel AI Gateway (POST /v1/evaluate, calibrated per-template relevance). Enables the engine on its own; falls back to deterministic on any gateway error. |
VIGIL_DECISION_BASE_URL=http://127.0.0.1:PORT |
Use a self-hosted decision engine (e.g. Haruspex / OpenJev) on loopback — same /v1/evaluate contract, selected keyless (the key authenticates the remote gateway only). Enables the engine on its own. |
VIGIL_DECIDE_TOP=N |
Run only the N most relevant templates (operator cap to cut the firehose). Default 0 = order only, no drop. |
VIGIL_DECISION_MODEL / VIGIL_DECISION_BASE_URL |
Override the model id / gateway base URL (defaults typesafe-ai/jev / https://ai-gateway.vercel.sh). |
Disabled by default — the template set is untouched unless you opt in.
Scope is ON by default: traffic is restricted to the target host(s) and
session-destroying paths (/logout, /delete-account, …) are skipped, so a scan
never wanders off-target. Every outbound request is gated at the HTTP client and
out-of-scope redirects are returned unfollowed. Cross-host detectors (cloud,
subdomain-takeover, the npm registry) and OOB callbacks use a separate unscoped
client, so they still reach their infrastructure. Use --no-scope to disable, or
--scope-host to broaden.
| Flag | Description | Default |
|---|---|---|
--no-scope |
Disable scope entirely (request any host) | off (scope on) |
--scope-host HOST |
Override the scoped hosts (repeatable; *.example.com) |
target host(s) |
--include-path RE |
Only request paths matching one of these regexps (repeatable) | |
--exclude-path RE |
Never request paths matching these regexps (exclude wins) | |
--no-default-excludes |
Keep session-destroying paths (/logout, /delete-account, …) in scope |
off |
--rate N |
Cap outbound requests per second across the whole scan | unlimited |
When a login is performed (--login-*), the session is polled during the scan
and re-authenticated on logout, so authenticated probes do not silently become
unauthenticated.
| Flag | Description | Default |
|---|---|---|
--session-check-url URL |
Authenticated-only URL polled for logout | first target |
--session-check-interval D |
Poll cadence | 1m |
--login-success doubles as the authenticated marker.
| Flag | Description |
|---|---|
--checkpoint FILE |
Record per-target progress so an interrupted scan can resume |
--resume FILE |
Skip already-scanned targets and carry their findings forward |
| Flag | Description |
|---|---|
--json |
JSON to stdout (shorthand for --format json) |
--html |
HTML report to stdout (shorthand for --format html) |
--format LIST |
Comma-separated: json, html, markdown, csv, sarif, junit, gitlab |
--output-dir PATH |
Output directory for report files |
-v, --verbose |
Verbose progress on stderr |
--verify |
Re-test each finding to confirm (reduces false positives) |
| Flag | Description |
|---|---|
--auth-a-cookie STRING |
Cookie header for identity A (the "victim") |
--auth-b-cookie STRING |
Cookie header for identity B (the "attacker") |
--auth-a-header KEY:VAL |
Per-identity-A header (repeatable) |
--auth-b-header KEY:VAL |
Per-identity-B header (repeatable) |
--idor-url URL |
Override URL for the cross-identity probe |
| Flag | Description |
|---|---|
--no-nuclei |
Skip the Nuclei binary even when it's on PATH |
--nuclei-tags LIST |
Tag filter forwarded to Nuclei (cve,rce) |
--nuclei-severity LIST |
Severity filter (high,critical) |
| Flag | Description |
|---|---|
--chrome-path PATH |
Explicit Chrome/Chromium binary |
--storage-inj |
Enable client-side storage injection probes |
--no-postmessage |
Disable the postMessage origin-validation probe |
The SPA crawl captures XHR/fetch endpoints (via CDP network events) and client-side routes registered through the History API (pushState/replaceState/ popstate), not just static anchors — so dynamic API surface is discovered.
Disable any detector with --no-<name>. Highlights:
--no-csrf, --no-tabnabbing, --no-jsdep, --no-data-exposure,
--no-admin-path, --no-api-version, --no-content-type, --no-sse,
--no-grpc-reflect, --no-prompt-injection, --no-xslt,
--no-saml-injection, --no-orm-leak, --no-type-juggling,
--no-dep-confusion, --no-token-entropy, --no-cache-deception,
--no-cache-poisoning, --no-css-injection, --no-deserialization,
--no-dom-clobber, --no-email-injection, --no-hpp,
--no-html-injection, --no-second-order, --no-ssi, --no-storage,
--no-discovery, --no-oob.
Aggressive probes are opt-in (mutate state or send heavy traffic):
--rate-limit, --redos, --h2-reset, --mass-assign,
--proto-pollution-server.
--nvd-api-key KEY (or NVD_API_KEY env) raises the NVD CVE lookup
limit from ~5 to ~50 requests / 30 seconds for the JS-dependency
detector.
113 native detectors mapped to OWASP WSTG / Top 10 / API Top 10 / CWE. Each finding ships with all four mappings plus CVSS scoring.
SQLi (**error-based + boolean-blind + UNION-based + time-based + stacked
- out-of-band**), XSS (reflected + stored via inject-crawl-confirm + DOM-based + blind/OOB), CMDi (error + time + OOB), SSTI (multi-engine — Jinja2 / Twig / Freemarker / Velocity / Mako / Smarty / ERB / Java), CSTI, NoSQL (error + boolean + time), LDAP, XPath, XXE (error + blind/OOB), JNDI / Log4Shell, SSI, XSLT, SAML (XSW + comment injection), email-header, CSV / formula, log injection, HTML / CSS / DOM-clobber injection.
LFI (with PHP wrappers), RFI, file upload (MIME / double-ext / null-byte bypass).
SSRF with cloud-metadata for AWS / Azure / GCP / Alibaba / Tencent / IBM / Oracle / IPv6, HTTP request smuggling, HTTP/2 desync, HTTP/2 advanced (CONTINUATION flood), HTTP/3 desync, race conditions (H/1 last-byte sync + H/2 single-packet), HTTP/2 rapid-reset (CVE-2023-44487, opt-in), second-order injection, deserialization, padding oracle.
JWT cryptanalysis (alg=none / RS→HS / embedded JWK / kid traversal / lifetime / weak-secret dict), JKU abuse, OAuth/OIDC discovery audit, OAuth flow testing, two-identity IDOR / BOLA, single-identity IDOR with numeric / UUID / hex mutation, BAC (broken access control), 403 bypass (path normalization + verb tamper + header tricks), CORS, mass-assignment with re-fetch verification, CSRF, session fixation, session lifecycle (timeout / concurrent / invalidation), MFA bypass, password reset flow audit, PHP type-juggling auth bypass, long-password DoS, SameSite cookie analysis, cookie tossing.
Web cache deception with unauth-replay verification, web cache poisoning via unkeyed-header reflection, cache key manipulation.
Security headers, open redirect, CRLF, header injection, host-header reflection, WebSocket (CSWSH / reflection), Server-Sent Events auth, gRPC reflection, TLS configuration, reverse-tabnabbing, XS-Leaks, ESI injection, X-Frame-Options / clickjacking.
Sensitive file exposure, cloud misconfig, subdomain takeover, DOM clobbering, server-side prototype pollution (opt-in), HPP, admin / debug path probe, content-type confusion, stack trace / debug info, data exposure, webhook signature validation.
OpenAPI spec runner (auth-bypass + undocumented verbs), OpenAPI semantic analysis, API version enumeration, ORM expansion / over-fetch, rate-limit burst probe (opt-in), GraphQL (introspection / alias batching / depth bomb / field suggestion / advanced injection).
DOM-XSS, client-side prototype pollution, DOM-based open redirect, client storage injection, postMessage origin validation, CSPT (client-side path traversal with JS taint tracking).
JS dependencies parsed from <script src> queried against
NVD CVE API,
dependency confusion manifest leak, subdomain takeover.
LLM prompt injection, ReDoS timing probe (opt-in), insecure-token entropy / sequential-id detector, DNS rebinding.
Blind detection via shared interactsh callback server — XXE, SSRF, CMDI, RFI, XSS (blind), second-order all participate.
vigil sast [path] [flags]vigil includes a native static-analysis engine for source-code and configuration auditing. It runs independently of the DAST scanner and produces findings in the same unified format.
15 pre-compiled regex patterns detect hardcoded credentials in source
files: AWS access keys, AWS secret keys, GitHub / GitLab / Slack / Stripe /
Google / Heroku tokens, JWTs, private keys (-----BEGIN ... PRIVATE KEY-----),
generic API keys and passwords in config, and database connection strings
(MongoDB / PostgreSQL / MySQL / Redis / AMQP). Evidence is auto-redacted in
findings.
Parses 8 manifest formats — package.json, package-lock.json, go.mod,
requirements.txt, Pipfile.lock, Gemfile.lock, composer.lock,
pom.xml — and queries the OSV.dev batch API for known
CVEs. Findings include CVE IDs, severity, affected version ranges, and fix
versions.
Detects security issues in common config files: secrets in .env files,
Dockerfile running as root (no USER directive), docker-compose.yml
with privileged: true or network_mode: host, nginx.conf with
server_tokens on.
| Flag | Description | Default |
|---|---|---|
--secrets-only |
Run only secret scanning | off |
--sca-only |
Run only dependency CVE scanning | off |
--config-only |
Run only config security checks | off |
--exclude-dirs LIST |
Skip directories (comma-separated) | vendor,node_modules,.git |
--concurrency N |
Concurrent file scanning workers | 10 |
--fail-on SEVERITY |
Exit code 2 on findings at or above this severity | |
--format LIST |
Output formats (json, html, markdown, csv) |
json |
--output-dir PATH |
Write reports to this directory |
vigil web [flags]Start the HTTP server and open the bundled web console in your default
browser. The console is a multi-page SPA — Dashboard, Targets, Scans, scan
detail (live findings triage, reports, compliance) and Settings — backed by a
JSON API that exposes every scanner feature. The same API also drives the
MCP server, so a human (browser), a script (REST) and an agent (MCP) all use
one control surface. vigil web --no-open doubles as a headless API server.
The New Scan and Settings screens drive the complete scan configuration from the browser — profile, per-detector on/off/auto for every detector, authenticated scanning and the two-identity IDOR probe, template and API-spec imports, custom headers, and intensity/crawl tuning — so nothing is CLI-only.
| Flag | Description | Default |
|---|---|---|
--port N |
Listen port | 8080 |
--listen ADDR |
Bind address; localhost binds loopback on both IPv4 and IPv6 |
localhost |
--api-key KEY |
Bearer token for API authentication (also VIGIL_API_KEY env) |
auto-generated |
--no-auth |
Disable API authentication entirely (trusted isolated hosts only) | false |
--state-file PATH |
Persist scans/targets/settings to disk so they survive a restart | in-memory |
--no-open |
Don't open a browser (headless / server use) | false |
Authentication is on by default: if no --api-key/VIGIL_API_KEY is set,
a random key is generated, printed once, and baked into the opened browser URL
(?key=…). The SPA reads it and sends it as a bearer token; SSE and report
downloads carry it as a query param.
| Method | Path | Description |
|---|---|---|
GET |
/api/health |
Health check (no auth) |
GET |
/api/version |
Server name and version (no auth) |
POST |
/api/scans |
Create a scan ({"target":"…","config":{…}}) |
GET |
/api/scans |
List scans (paginated: ?offset=0&limit=25) |
GET |
/api/scans/{id} |
Scan status + summary |
DELETE |
/api/scans/{id} |
Cancel a running scan |
GET |
/api/scans/{id}/progress |
Live progress |
GET |
/api/scans/{id}/findings |
Findings of a completed scan |
GET |
/api/scans/{id}/events |
Server-Sent Events: live findings |
GET |
/api/scans/{id}/report?format= |
Download report (json, sarif, html, markdown, csv, …) |
GET |
/api/scans/{id}/compliance?framework= |
Assess against pci-dss, hipaa or iso-27001 |
POST |
/api/scans/{id}/findings/{fid}/fp |
Mark/clear a finding as a false positive |
GET |
/api/profiles |
Scan profiles |
GET |
/api/config/defaults |
Controllable detector names + profiles |
GET |
/api/tools |
External tools and their availability |
GET/PUT |
/api/settings |
Default scan config applied to new scans |
GET/POST |
/api/targets |
List / create saved targets |
DELETE |
/api/targets/{id} |
Remove a saved target |
POST |
/api/targets/{id}/scan |
Scan a saved target |
The config object in a scan request mirrors the full scanner configuration:
transport (rate, concurrency, timeout, headers, cookie, user-agent, method,
TLS), scope, auth/identity, crawl, templates, and a detectors map that
toggles any detector by short name (unknown names are rejected).
- Binds to loopback (
localhost, both IPv4 and IPv6) by default — pass--listen 0.0.0.0to expose externally (requires an API key). - Authentication is required by default; every endpoint except
/api/healthand/api/versionrequires the key (constant-time comparison).--no-authopts out for a trusted isolated host. - Scan targets are validated:
http/httpsonly, private/loopback IPs rejected (SSRF protection with IPv6-mapped IPv4 normalization). - Concurrent scans are limited to 3 by default; the job store evicts the oldest completed jobs after 1000 entries.
vigil mcp [--state-file PATH]Expose vigil's control surface over the Model Context
Protocol so MCP-speaking agents can drive
scans. vigil mcp serves over stdio (an agent spawns the process); a
running vigil web also serves the same tools over streamable HTTP at
/mcp, behind the same API key. Both transports are thin wrappers over the
REST service, so there is no behavioural drift between them.
Tools: scan_start, scan_status, scan_list, scan_findings,
scan_report, scan_cancel, list_profiles, config_defaults,
list_tools, compliance_assess, fp_mark, target_list, target_scan.
Point --state-file at the same file a vigil web uses to share scan state
between them.
Two capabilities deserve special call-out because they are structurally beyond Nuclei templates:
Navigates a target in a real browser, dispatches a synthetic
MessageEvent claiming an attacker origin, then diffs DOM / storage
sinks. Listeners that mutated innerHTML / location / localStorage
/ sessionStorage / documentCookie without validating
event.origin are reported with severity graded by which sink
was reached.
vigil scan --no-postmessage=false https://app.example.com/Constructs two HTTP clients carrying distinct auth state and probes the same URL with each. When identity B's response carries a body similar (Jaccard ≥ 0.85) to identity A's private response — and contains sensitive-data markers — emit a Critical finding. Otherwise High when the unauthorised access is confirmed, Medium when only the application precondition is observed.
vigil scan https://api.example.com/v1/users/42 \
--auth-a-cookie "session=alice" \
--auth-b-cookie "session=bob"vigil ships 113 in-process detectors plus 8 external tool wrappers. The smart dispatcher runs tools automatically based on what the native detectors discover — no manual tool selection needed.
Two modes run together:
- Autonomous — core tools (SQLMap, Dalfox, Nikto, Nuclei) always run at full strength with their own crawl and parameter mining. WPScan runs when WordPress is detected. Ghauri/Commix/Tplmap run in thorough mode.
- Focused — when the native scanner confirms a vulnerability, the
dispatcher launches a pinned tool run on that exact parameter with
context hints (e.g.,
sqlmap -p username --dbms=PostgreSQL). Focused mode is additive — it never replaces autonomous.
| Tool | Status | Purpose | Dispatch |
|---|---|---|---|
| Built-in template engine | native | Nuclei-compatible: all protocols, unsafe-raw, pipeline, interactsh OOB, 20 headless actions | Always |
| Nuclei | wrapped | Upstream community templates (15,000+) + DAST fuzzing (-dast) |
Always (autonomous) |
| SQLMap | wrapped | Deep SQLi with --crawl --forms --smart |
Always + focused with --dbms hint |
| Dalfox | wrapped | XSS scanning with param mining and DOM analysis | Always + focused with --param |
| Nikto | wrapped | Web server misconfig, outdated software, sensitive files | Always (autonomous) |
| WPScan | wrapped | WordPress plugin/theme/core CVEs | When WordPress detected |
| Commix | wrapped | OS command injection exploitation | Thorough + focused |
| Ghauri | wrapped | Fast SQLi detection (sqlmap alternative) | Thorough + focused |
| Tplmap | wrapped | SSTI template engine detection | Thorough + focused |
vigil tools list shows availability and version. vigil tools check
runs a health check. Missing binaries are not fatal — the scan proceeds
without them. Install tools to expand coverage.
The CLI already carries everything a pipeline needs: distinct exit codes
(0 clean, 1 operational error, 2 the --fail-on severity gate was
met), sarif/junit/gitlab report formats, and --baseline/
--fail-on-new for incremental (diff-only) scanning. Reports land as
<output-dir>/vigil-report.<ext> (.sarif, .xml for JUnit,
.gitlab.json for GitLab's code-quality format).
GitHub Actions — use the packaged action (action.yml at the repo
root). It builds vigil from Dockerfile on first use (no external image
registry needed) and uploads the SARIF report to code scanning automatically:
- uses: actions/checkout@v4
- uses: TyrusRC/vigil@main
with:
target: https://staging.example.com
profile: normal
fail-on: high
format: sarif,junitGitLab CI / Jenkins / Azure DevOps — no plugin needed; call the binary
directly and point the platform's own report-ingestion step at
vigil-report.xml (JUnit) or vigil-report.gitlab.json (GitLab
code-quality):
vigil scan "$TARGET_URL" --format junit --output-dir report --fail-on highA non-zero exit (1 or 2) fails the stage the normal way — sh/script
steps already propagate it, so no wrapper plugin is required.
Incremental scanning (any CI system) — cache the previous run's JSON report as a pipeline artifact and gate only on new findings:
vigil scan "$TARGET_URL" --format json,junit --output-dir report \
--baseline previous-report/vigil-report.json --fail-on-new --fail-on high| Capability | vigil | Nuclei | Burp Suite Pro | Acunetix |
|---|---|---|---|---|
| Injection classes | 113 native detectors + 8 tools | 20+ (template) | 15+ native | 52 PerScheme |
| Auth / access testing | IDOR/BOLA, BAC, 403 bypass, JWT, OAuth, MFA, session lifecycle | Template-only | Extensions | Basic |
| Protocol attacks | Smuggling, HTTP/2 desync, H/2 rapid-reset, H/3, race conditions | Partial | Good | Minimal |
| Client-side / DOM | postMessage, CSPT taint, DOM clobber, XS-Leaks, prototype pollution | Partial | Good | Good (DeepScan) |
| API testing | GraphQL (introspection + DoS + injection), OpenAPI semantic, ORM leak | Templates | API scanning | 7 API checks |
| Tool orchestration | Smart dispatch: auto sqlmap/dalfox/commix with DBMS hint | None | Extensions | None (monolith) |
| Template ecosystem | Built-in engine + Nuclei 15K+ | 15,000+ community | BApp Store | None |
| SAST | Secrets + SCA + config | File templates only | None | SCA add-on |
| AI finding triage | Haruspex adjudication | None | None | None |
| Smart defaults | Zero-flag scanning, auto-detect API spec/SPA/tech | Manual config | Wizard | Profile-based |
| CI/CD | SARIF, JUnit, GitLab, GitHub Action, baseline diff | Good | Plugin | Good |
| Authenticated scanning | Form + headless login, session keepalive | Headers only | Macro recorder | LSR recorder |
| IAST | Planned (taint markers + sink hooks) | None | None | AcuSensor |
| Cost | Free (Apache 2.0) | Free (MIT) | $449/yr | $4,495+/yr |
- Smart tool orchestration — native detectors find injection points in seconds, then auto-dispatch sqlmap/dalfox/commix with the exact parameter and DBMS hint. No manual tool selection or flag tuning.
- Zero-flag scanning —
vigil scan <url>auto-detects API specs (OpenAPI/Swagger), SPA frameworks (React/Angular/Vue), and tech stack. Enables the right detectors, crawl mode, and tools automatically. - Coverage summary — every scan reports what was tested and what was skipped (and why), so the result is never silently incomplete.
- AI-based finding triage (Haruspex) — per-finding "real vs noise" probability scoring, reducing manual triage.
- Two-identity IDOR/BOLA as a first-class, native capability.
- Session keepalive with auto-reauth — detects logout via canary URL and re-authenticates.
- 17-source parameter auto-discovery — forms, cookies, headers, JSON body, path segments, JS storage, XML body, robots/sitemap, HTML comments, JS routes, multipart, OpenAPI, GraphQL introspection, reflected-param brute-force, JS fetch/axios/jQuery extraction, and link query params. All run per crawled page (BFS, default 30 pages).
- Body-first param priority — body params (username, password, email) tested first; JS noise and headers tested last. Ensures injectable params are reached even under time constraints.
- 40+ framework-specific weak secrets — Flask, Django, Express, Rails, Laravel, Tornado, Yii2, Play, Spring Boot, Next.js cookie/JWT secret brute-force.
- Acunetix-derived payloads — math-based boolean differential
(
5*5=25 vs 5*5=26), XOR sysdate MySQL time-based, PostgreSQL SELECT-match time-based.
flowchart LR
CLI -->|targets + config| AutoConfig[Auto-Config]
AutoConfig -->|detect API spec, SPA, tech| Scanner
CLI -->|paths| SAST[SAST engine]
Scanner --> Discovery[Discovery · 17 sources + link crawler]
Discovery --> Params[(Parameters)]
Scanner --> Detection[113 native detectors]
Detection --> HTTP[HTTP client · scope · throttle]
Detection --> Headless[Headless pool · go-rod]
Detection --> OOB[Interactsh OOB]
Detection -->|injection candidates| Dispatcher[Smart Dispatcher]
Scanner --> Templates[Nuclei template engine]
Dispatcher -->|autonomous| Tools[SQLMap · Dalfox · Nikto · Nuclei]
Dispatcher -->|focused -p param --dbms| SQLMap[SQLMap / Ghauri]
Dispatcher -->|focused -p param| Dalfox[Dalfox / Commix]
Templates -->|HTTP · DNS · File · Headless · Workflow| HTTP
Scanner --> Tools[External tools]
Tools --> NucleiBin[nuclei]
Tools --> SQLMapBin[sqlmap]
Detection --> Verify[Verification]
Verify --> Haruspex[Haruspex AI triage]
Haruspex --> OWASP[OWASP + compliance mapper]
SAST --> Secrets[Secret scanner]
SAST --> SCA[SCA · OSV.dev]
SAST --> Config[Config auditor]
OWASP --> Reporter
SAST --> Reporter
Reporter --> JSON & HTML & SARIF & CSV
The DAST orchestrator dispatches in five phases:
- Discovery — enumerate every injectable surface from 13 sources (forms, cookies, headers, JSON, XML, multipart, paths, JS storage, comments, JS routes, OpenAPI, GraphQL introspection, robots/sitemap).
- Parameter-injection — for each discovered parameter, run only
the detectors that make sense for its
Location(query/body/path/ header/cookie/storage).SendPayloadAtdispatches into the correct transport. - URL-level — IDOR, two-identity BOLA, CORS, smuggling, race, cache deception, postMessage probe, JWT, OAuth, GraphQL, the OpenAPI runner, and ~40 more, all in parallel goroutines.
- Stored XSS (opt-in) — inject canaries, crawl, match reflections, confirm with real payloads.
- OOB — poll interactsh callbacks to confirm blind cases (XXE, SSRF, CMDI, XSS, second-order).
Post-scan: verification re-tests findings, then Haruspex AI triage annotates each with a "real vs noise" probability.
cmd/vigil/ CLI entry point (Cobra)
internal/
api/ HTTP JSON API server (vigil web)
auth/ Form + headless login, session capture
checkpoint/ Scan resume / checkpoint persistence
compliance/ PCI DSS / HIPAA / SOC 2 mapping
core/ Finding, Target, Severity, Parameter
crawl/ State-aware BFS crawler with form submission
decision/ Haruspex / Jev template-relevance + finding triage
detection/<module>/ 110+ per-detector packages (one per category)
discovery/ Auto-discovery pipeline (13 sources)
headless/ Rod-backed browser pool + 20 headless actions
http/ HTTP client with location-aware payload dispatch
owasp/ WSTG / Top-10 / API-Top-10 mappers
payloads/ Risk-gated payload data per category
reporting/ JSON / HTML / Markdown / CSV / SARIF / JUnit reporters
sast/ Native SAST engine (secrets, SCA, config)
scanner/ DAST scan orchestration
scope/ URL scope policy (host + path rules)
scoring/ CVSS scoring
session/ Session keepalive with auto-reauth
templates/ Nuclei-compatible template engine (full parity)
tools/ External tool wrappers (sqlmap, nuclei)
verification/ Finding re-test verification
webui/ Embedded SPA dashboard
data/ Wordlists and fingerprints
web/ Dashboard source (React)
Source files are kept under 500 lines; refactor when a file grows past it.
make build # produce bin/vigil
make test # unit tests
make test-short # skip integration / network-bound tests
make test-race # tests with -race
make test-cover # coverage report
make test-integration # requires sqlmap / nuclei / ffuf binaries
make test-e2e # end-to-end scans
make lint # golangci-lint
make fmt # go fmt + gofumpt
make vet # go vet
make security # gosec
make check # fmt + vet + lint + security + race (run before PR)
make bench # benchmarksThis project follows strict TDD (CLAUDE.md). Write the failing test first; never add production code without a covering test. New detectors should:
- Live under
internal/detection/<module>/withdetector.go,detector_test.go,doc.go. - Implement the same shape as existing detectors (constructor takes
*internal/http.Client,Detect(ctx, target, opts)returns*DetectionResult). - Map each finding to
WSTG-…,A0X:2025, optionalAPIX:2023, and the relevant CWE viaFinding.WithOWASPMapping. - Be wired into
internal/scanner/runner_url.go(URL-level) orinternal/scanner/runner_param.go(parameter-level), and gated behind anEnable<X>flag inInternalScanConfig.
Issues and pull requests are welcome.
- Fork and create a feature branch (
feature/<short-name>orfix/<short-name>). - Write tests first — every PR must keep
make checkgreen and uphold the 80%+ coverage threshold for security-critical packages (internal/detection/,internal/http/). - One detector per PR keeps reviews tractable.
- No co-author trailers other than yourself; don't reference AI tools in commit messages.
- Conventional Commits (
feat:,fix:,refactor:,test:,docs:,chore:) — seegit logfor in-repo style.
Run make check locally before opening a PR.
- Headless crawl for SPAs — full headless-browser crawl with client-side route discovery for React/Angular/Vue applications
- Coverage tracking — record every (endpoint, param, detector) tuple tested and surface untested areas in the coverage summary
- Additional tool integrations — feroxbuster (directory fuzzing), arjun (hidden param discovery), katana (advanced crawling)
- IAST (Interactive Application Security Testing) — lightweight taint-marker sensor (PHP/Node/Python) that hooks sinks (SQL_Query, Sys_Command, File_Open, URL_Open, Unserialize, etc.) and confirms payloads reach dangerous functions. Raises confidence from "medium" to "confirmed" when the marker reaches the sink. Architecture: inject taint markers in DAST payloads → sensor in the target app detects marker at sink → reports back via HTTP callback. Not a full code-level IAST — a focused sink-confirmation layer.
- Proof-based scanning — multi-round verification: DAST detection → replay confirmation → OOB callback → stored-XSS revisit → IAST sink confirmation. Each layer raises confidence.
- Session maintenance loop — auto-detect logout and re-authenticate
during long scans (framework exists via
--login-*+--session-check-url) - Incremental scanning — diff against a prior scan, report only new findings, skip endpoints that haven't changed
- Tech-to-CVE correlation — map detected tech stack + version to known CVEs (4,717 fingerprints extracted from Acunetix DB available)
vigil is a defensive security tool. Use it only against systems you own or have explicit written authorisation to test. Unauthorised scanning is illegal in most jurisdictions.
If you find a security issue in vigil itself (not in a target), open a private GitHub Security Advisory rather than a public issue.
Licensed under the Apache License, Version 2.0. See LICENSE for the full text.