vigolium kit is a family of small, stateless primitives carved out of the scanner’s own engine — no database, no project scope, no scan pipeline. Each one is a single transform or probe: it reads files or stdin, honours -j/--json for machine output, and gates via exit codes.
Added in v0.4.1. They exist because the useful parts of a scanner are often wanted outside a scan — grepping a repo for leaked credentials, unminifying one bundle, cracking one JWT — and shelling out to five separate tools to do it is the wrong shape.
These are primitives: they do one job and report raw output, never a vulnerability verdict. They touch no project database, so nothing is persisted — pipe the output where you need it. For findings that persist, use
vigolium scan or the agent modes.The commands
Every command reads
- (or no argument) as stdin and takes -j/--json for a single structured object on stdout. Human notes go to stderr, so a pipe stays clean.
secret-scan
Scan bytes for leaked secrets with the embedded detection catalog (~12k kingfisher + Vigolium rules, pure Go, no network). Positional arguments are files or directories, walked recursively; - or no argument reads stdin.
JSON shape:
{files_scanned, count, matches:[{rule_id, rule_name, confidence, secret, entropy, file, line, start, end}]}.
Reports where a secret is, never whether it is exploitable. Obvious placeholders (…EXAMPLE, 123456… sequences) are safelisted away, so test with realistic-looking values.
js-beautify
Unminify and unpack minified or bundled JavaScript with the embedded jstangle tool (webcrack — no eval-based deobfuscation). The argument is a local file, an http(s):// URL that gets fetched, or -/no argument for stdin.
--extract also runs endpoint extraction.
JSON shape:
{source, status, changed, format, module_count, module_paths?, bytes_in, bytes_out, content, endpoints?, diagnostics?, output_path?, modules_dir?, modules_written?}. Endpoints carry {url, method, params, body, headers, cookies, extractor, confidence, module_path?}.
A big bundle returns partial, and that is the good outcome. A script dense enough to blow the AST budget cannot be parsed whole, so the engine unpacks it and analyzes each module separately (ast_budget_recovered_by_module_scan). Those endpoints carry extractor: "bundle-module" and a module_path, with real methods, headers and body templates. A partial from that path is far better data than a complete from a small file.
An empty method means unresolved, not GET. The large-input-string-fallback extractor is a regex sweep over source no analyzer could parse; it recovers URLs only. Treat confidence: "low" plus an empty method as a lead to confirm, never as a request to replay.
For a bundle of any size, prefer --modules <dir> over reading content: a 400-module document is one 5 MB blob, and a directory is greppable.
oast (new / poll)
Generate interactsh out-of-band callback URLs, and later poll for the DNS/HTTP/SMTP interactions they received — the primitive behind blind SSRF/XXE/RCE/Log4Shell confirmation.
State lives in a session file, so minting and polling are separate fire-and-forget invocations with no long-running process between them.
poll JSON: {server, session, count, interactions:[{protocol, unique_id, full_id, remote_address, timestamp, raw_request, raw_response}]}.
harvest
Collect historically-known URLs for one or more domains from public archives and indexes — the same source set as the scan’s external-harvest phase. Wayback, Common Crawl, AlienVault OTX and Arquivo are keyless and on by default; urlscan and VirusTotal join when their key is configured under external_harvester.
A URL argument is reduced to its host; - reads domains one per line from stdin.
-j yields {domains, sources, count, urls}.
jwt-crack
Brute-force a JWT’s HMAC signing secret (HS256/384/512) against a wordlist. A token declaring an asymmetric algorithm (RS*/ES*/PS*) is additionally tried under every HMAC variant — the algorithm-confusion attack — and a match is labelled as such. The token is a positional argument or -/stdin; a leading Bearer is stripped.
JSON:
{alg, cracked, secret, matched_alg, candidates_tried, wordlist, header, payload}. The recovered secret is printed in full — that is the point of the command.
wordlist
List the embedded wordlists, or print one to stdout so it can be piped into another tool.
jwt alias. Built-ins: dir-short, dir-long, file-short, file-long, fuzz, jwt.secrets.list.
payload
Print the built-in fuzzing payloads for one or more classes, one per line — the same catalog behind vigolium fuzz --class.
cmdi, crlf, lfi, open_redirect, path_traversal, sqli, ssrf, ssti, xss, xxe, plus aliases (sql → sqli, traversal → path_traversal). JSON: {classes, count, payloads}.
tmp-clean
Remove the temporary scratch Vigolium left in the system temp directory. Added in v0.5.0.
JSON shape:
{temp_dir, scratch_root, abandoned_removed, legacy_removed, total_removed, duration}.
As of v0.5.0 every scan allocates its scratch under one root and removes the whole thing on exit, so a run that finishes — or is interrupted — cleans up after itself. This command is for what is already there: scratch from runs that were killed, and the loose per-store directories that earlier versions allocated straight into the temp directory.
That backlog gets large, and it is also a startup cost. One workstation had accumulated 71,614 leftover dedup directories totalling 108 GB, and separately 3,384 stranded Chromium profiles worth 104 GB — the spidering browser never called go-rod’s
launcher.Cleanup(). Vigolium’s own dependencies used to sweep the whole temp directory at startup, so the litter made every invocation slower in proportion to how much of it there was.Only names Vigolium itself allocates are touched, and only entries untouched for --max-age, so scratch belonging to a scan running right now is never taken.Gotchas
- Stateless by design. Nothing lands in the project database — pipe or redirect the output yourself.
oast newdoes not tear down the session. Closing an interactsh client deregisters it server-side, sonewmints, saves and exits without closing; the session stays alive forpoll. Usepoll --deregisterto destroy it explicitly when you’re done.oast --intervalis auto-shrunk below--wait(the poll ticker only fires after one full interval), so even a short--waitpolls at least twice.secret-scansafelists placeholders.AKIA…EXAMPLEand123456-sequence tokens are treated as benign.js-beautifynever exits non-zero for a degraded analysis. A bundle that only half-analyzed still exits0;statusanddiagnosticsare the only signal.js-beautify --max-input-mbcannot raise the ceiling. The service takes the lower of this and its own limit (10 MiB by default), so a larger value is silently ignored. Raisejstangle.hard_input_mbin config instead.- Exit 3 is a gate, not an error.
secret-scan --fail-on-matchandjwt-crack --fail-on-crackexit3on a hit; otherwise the usual0success /1error /2usage error applies. See the exit-code table.
