
Runtime vulnerability scanner: finds CVEs in the services actually running on a host and ranks them by network exposure.
threat-finder finds the vulnerable software actually running on a host — not
what a manifest claims — and tells you which findings are network-reachable.
It resolves each running service (and, with --scope all, every installed OS
package) to an exact Package-URL and
matches it against the OffSeq Radar catalog using
ecosystem-native version rules, so backported/fixed builds aren't false-flagged.
Vulnerability summary (highest risk first):
openssh-server@1:8.9p1-3ubuntu0.6 — 1 finding(s) [PUBLIC tcp 0.0.0.0:22]
[ACT-NOW 92] HIGH CVE-2024-6387 [KEV] regreSSHion: remote code execution in OpenSSH
→ fix: 1:8.9p1-3ubuntu0.10 https://radar.offseq.com/threat/…
[email protected] — 1 finding(s)
[SCHEDULE 41] MED CVE-2023-44487 HTTP/2 Rapid Reset
2 confirmed finding(s) across 2 asset(s); 1 exposed, 1 known-exploited.
brew install offseq/tap/threat-finder # Homebrew (macOS/Linux), prebuilt
cargo binstall threat-finder # prebuilt binary, no toolchain
cargo install threat-finder # from source
Prebuilt archives for Linux/macOS (x86_64 + arm64) and Windows (x86_64) are on the releases page. Requires Rust ≥ 1.87 to build from source. Linux, macOS, the BSDs, and Windows are all supported.
export OFFSEQ_API_KEY=... # from https://radar.offseq.com/console
threat-finder
Scans the running services, prints a risk-ranked summary, and writes the full
JSON report to /tmp/threats.json. Add --scope all to also scan every
installed OS package.
threat-finder [OPTIONS]
| Flag | Description |
|---|---|
-o, --output <PATH> | Write the JSON report to PATH (default: prompt, or /tmp/threats.json) |
--json | Print the JSON report to stdout instead of a file |
--scope <SCOPE> | running (default) or all (+ every installed OS package) |
--severity <LEVEL> | Only report findings at/above critical|high|medium|low |
--strict | Drop coordinate-unconfirmed findings (report only confirmed) |
--fail-on <WHAT> | Exit 5 if matching findings exist: any|critical|high|medium|low|kev|exposed |
--sarif <PATH> | Also write a SARIF 2.1.0 report (for code-scanning UIs) |
--include <GLOB> / --exclude <GLOB> | Filter assets by name glob (repeatable) |
-q, --quiet | Suppress the banner, progress, and summary |
--no-color | Disable ANSI colors |
-y, --yes | Assume defaults, never prompt (CI/cron) |
--reset | Re-enter the API key, ignoring the saved one |
--register | Register the scanned host with Radar for continuous monitoring (no prompt) |
--no-register | Don't register or prompt for monitoring this run |
--host-name <NAME> | Friendly hostname to send with a registration |
--unregister | Remove this host's inventory from Radar and exit |
--windows-missing-updates | (Windows) Also list pending security updates from the Windows Update Agent (online scan; run elevated) |
-h, --help / -V, --version | Help / version |
# CI: only high+ findings, JSON to stdout, no prompts
OFFSEQ_API_KEY=… threat-finder --yes --json --severity high > report.json
# Fail the build only when a network-exposed service has a known-exploited CVE
OFFSEQ_API_KEY=… threat-finder --yes --quiet --fail-on exposed
Exit codes: 0 ok · 1 lookup/IO error · 2 no API key · 3 unsupported
OS · 4 rate limit/quota, or API access required (upgrade needed) · 5
--fail-on threshold met.
API key (get one from the Radar Console), resolved in order:
OFFSEQ_API_KEY environment variable (best for CI/cron).$XDG_CONFIG_HOME/offseq-rust/config.toml (0600),
unless --reset is given.Non-interactive (--yes / no TTY) with no key available exits 2.
Set OFFSEQ_CONFIG_DIR to override where the config lives (default: the OS
per-user config dir) — handy for containers/CI that need a deterministic path.
Exact-coordinate matching. Each asset becomes a purl carrying its full
version (epoch + distro revision) and a ?distro= qualifier, e.g.
pkg:deb/ubuntu/openssh-server@1:8.9p1-3ubuntu0.6?distro=jammy. The inventory is
matched in batched POST /match/batch calls (one request per tier-sized chunk)
server-side, with ecosystem-native version rules (dpkg/rpm/apk/semver) — so a
backported-and-fixed build like 1.18.0-6+deb11u3 is correctly not flagged, and
there's no client-side version guessing. Findings are split by the API's
confirmed flag: confirmed matches are reported; coordinate matches whose
version can't be confirmed are surfaced separately as unconfirmed / triage
(excluded from the count, byCve, and --fail-on; drop them with --strict).
Network-exposure correlation. Manifest scanners (Trivy, Grype, osv-scanner)
read package lists; external scanners (Nessus, OpenVAS) need a second host. This
tool maps each running service's process to the sockets it is listening on
(/proc/net on Linux, lsof on the other Unixes, Get-NetTCPConnection /
netstat on Windows) and classifies reachability —
loopback / private / public. A vulnerable service on 0.0.0.0 is a very
different risk from one on 127.0.0.1: findings rank exposed-first and
--fail-on exposed gates CI on exactly that. No packets are sent. Findings also
carry CISA KEV and EPSS.
Exposure-aware prioritization. Every finding gets a riskScore (0–100) and an
SSVC-style decision band — act-now · soon · schedule · track — fused
from severity, EPSS, KEV, and the owning asset's network exposure. The summary
leads each line with a [ACT-NOW 92]-style badge and sorts by it, so the handful
of public-facing, known-exploited issues float to the top of a noisy host. The
score uses the same formula locally and server-side (the Radar monitoring view
adds a small bonus when a KEV finding is past its due date — a date the CLI
doesn't have), and appears in --json and SARIF (properties).
A one-off scan is a point in time. Register a host once and Radar keeps watching: when a newly-published CVE affects one of its coordinates, you get an alert (email + Console), prioritized by exposure — no re-scan needed.
After an interactive scan, the tool asks:
Add these 42 services to Radar for continuous monitoring & alerts? [Y/n/never]
Y registers this host; n skips this run; never remembers your choice (it's
saved to the config and you won't be asked again). On a re-scan it also reports
drift (+added / -removed / ~changed) and any findings new since your last
scan. Manage your hosts — toggle monitoring, view findings, deregister — under
Inventory in the Radar Console.