Skip to main content
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.
By default it writes beautified source to stdout, emitting the input unchanged when it is neither minified nor bundled. --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?}.
Read status before trusting endpoints. complete is a clean AST pass. partial means some stages did not run, and the diagnostics codes say which. failed means the analysis produced nothing of its own. The exit code is 0 either way — a degraded analysis is never non-zero, so status and diagnostics are the only signal.
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}]}.
Callbacks to the default public oast.pro server are visible to whoever operates it. Point --server/--token at a self-hosted interactsh to keep them private.

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.
Plain mode streams deduped URLs one per line, so it pipes straight into another tool. -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.
A name matches the embedded filename, its basename without extension, or the 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.
Classes: 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 new does not tear down the session. Closing an interactsh client deregisters it server-side, so new mints, saves and exits without closing; the session stays alive for poll. Use poll --deregister to destroy it explicitly when you’re done.
  • oast --interval is auto-shrunk below --wait (the poll ticker only fires after one full interval), so even a short --wait polls at least twice.
  • secret-scan safelists placeholders. AKIA…EXAMPLE and 123456-sequence tokens are treated as benign.
  • js-beautify never exits non-zero for a degraded analysis. A bundle that only half-analyzed still exits 0; status and diagnostics are the only signal.
  • js-beautify --max-input-mb cannot 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. Raise jstangle.hard_input_mb in config instead.
  • Exit 3 is a gate, not an error. secret-scan --fail-on-match and jwt-crack --fail-on-crack exit 3 on a hit; otherwise the usual 0 success / 1 error / 2 usage error applies. See the exit-code table.