Introducing the StackRadar CLI: scan what your cluster is actually running
stackradar scan is a free, Apache-2.0 CLI that finds known and exploited CVEs in every image running in your Kubernetes cluster — no agent, no account, no telemetry. Why it enumerates from the kubelet instead of your manifests, and what it deliberately does not do.
StackRadar Team
· 8 min read
Every platform engineer knows the moment: a CVE hits the news, and someone asks "are we affected?". The honest answer usually takes an hour — find every cluster, work out which images are deployed, scan them one at a time, and hope nothing was redeployed since the manifest you are reading was written. We built stackradar scan to make that answer take about a minute, and this post explains the one design decision that shapes everything else about it: where the list of images comes from.
Manifests drift; the kubelet does not
Most ways of answering "what are we running?" start from what was declared: Deployment specs, Helm values, the manifests in your GitOps repo. That list is wrong in quiet, systematic ways:
- A mutable tag (
:latest,:v2, even a re-pushed:1.4.2) can point at a different image than it did when the pod started. The spec has no opinion; the node knows exactly which digest it pulled. - Admission webhooks inject containers the manifest never mentions — service-mesh sidecars, secrets agents, tracing proxies. They run in your cluster with your network access, and a spec-derived inventory has never heard of them.
- Clusters accumulate things nobody's repo declares: a colleague's
kubectl run, an operator's workloads, a one-off Job that never got cleaned up.
The kubelet, meanwhile, reports ground truth. Every running pod's status.containerStatuses[].imageID carries the exact digest the container runtime is executing — app containers, init containers and injected sidecars alike. So that is where the CLI starts: it lists pods through your existing kubeconfig, collects the digests the kubelets report, deduplicates them (a hundred replicas of one digest is one scan), pulls each image from your registry, and matches its OS and language packages against OSV using the embedded osv-scanner library. Findings are attributed back to the namespaces and pods that run them, and anything in CISA's Known Exploited Vulnerabilities catalogue is flagged so the CVEs being exploited in the wild sort first.
A useful side effect of pods-only enumeration: the CLI needs list pods — the same permission as kubectl get pods — and nothing else. Tools that walk the workload hierarchy from the spec side need to list Deployments, StatefulSets, CronJobs and a dozen other kinds cluster-wide. If you can look at pods, you can run this.
One command
brew install lockdep/tap/stackradar
# or
curl -fsSL https://raw.githubusercontent.com/lockdep/stackradar-cli/main/install.sh | sh# every running image in the current kubeconfig context
stackradar scan
# a specific context, two namespaces
stackradar scan --context prod -n payments -n checkout
# one image, no cluster needed
stackradar scan --image nginx:1.27
# a self-contained HTML report, or a live local dashboard
stackradar scan -o html --file report.html
stackradar scan --serveOutput is a severity-sorted table by default, JSON when a machine is reading, or a single self-contained HTML file — the same interactive report --serve opens locally — that you can attach to a ticket and open offline. In CI it gates:
# exit 2 if anything running is in CISA's Known Exploited Vulnerabilities catalogue
stackradar scan --fail-on kevExit codes follow Grype's convention (0 clean, 1 error, 2 threshold met), so it drops into pipeline logic written for other scanners unchanged. Image pulls use the registry credentials you already have — ~/.docker/config.json, credential helpers, cloud keychains — or, with --use-pull-secrets, the cluster's own imagePullSecrets; the report then says which secrets were used.
What it deliberately does not do
A launch post that only lists strengths is an advert, so here are the limits, stated the way we'd want another vendor to state them:
- It is a snapshot. A scan is true for the moment it ran. Tomorrow's advisory can make today's clean image vulnerable without a single deploy. The CLI does not watch for that — keeping the answer current is what the in-cluster scanner is for, and it is the part of StackRadar we charge for.
- It inherits osv-scanner's coverage. Debian, Ubuntu, Alpine and the mainstream language ecosystems are well covered; some enterprise distros are thinner. If your base images live in a thin spot, a distro-native scanner will see things this does not.
- Counts will not match Trivy or Grype exactly. No two scanners agree on the same image: different catalogers find different packages, and severity methodology differs — we take the maximum CVSS an OSV advisory carries, where Trivy prefers the distro's own assessment, so our numbers tend to read higher on the same image. The tools roundup explains where the disagreements come from.
- It can only scan what your machine can pull. An image behind credentials you do not hold is reported as not reachable from here, never silently skipped and never guessed at.
- Scanning from the spec side has its place. In CI, before deploy, the artefact you are about to ship is exactly what you want to scan — Trivy and Grype are good at that job, and the CLI's
--imagemode does it too. The running-cluster question is simply a different question, and it is the one that gets asked during an incident.
Nothing phones home
--use-pull-secrets, and credentials stay in memory for the pull.The CLI is Apache-2.0, a single static Go binary for Linux, macOS and Windows, and every release's checksums are signed with cosign from the repository's GitHub Actions identity — the verification commands are on the CLI page.
Where it fits
stackradar scan is the free, standalone answer to "are we affected, right now?" — grab it from GitHub or the CLI page, run it against your cluster, and tell us what it gets wrong; issues and scan discrepancies are exactly the feedback we want. When the question becomes "will we know when we become affected?", that is the continuous half of StackRadar: an in-cluster agent that keeps a CycloneDX SBOM of every running image and re-matches it as advisories land, with every cluster in one dashboard.