Stop typing your software inventory. Import it in one command.
Manual entry is fine for a demo and useless for a real fleet. Here's how I populate My Stack from a host scan or an SBOM — and keep my inventory off a website entirely if I want.
I'll say the quiet part first, because a previous walkthrough got the objection right: typing your software into a website does not scale, and if your inventory lives in a scanner or a CMDB, hand-copying it into a second place is a chore that rots. A real environment is hundreds of products across dozens of versions. So the honest way to fill My Stack isn't the text box — it's an import. Here's how I do it.
Scan a host
The fastest path is to let the CLI read what's actually installed on a machine and push the package list up. Every row lands tagged os-scan with the host name, so you can see later exactly where each product came from.
$ cvetools stack scan$ # reads installed packages on this host, normalizes them,$ # and upserts them into your stack (source=os-scan, host=this-box)That's where the operating-system packages in my stack came from — sudo, openssl, openssh, systemd, curl and the rest. I never typed them, and the SOURCE column proves it.

Import an SBOM
If you already build a software bill of materials, point it at My Stack. A CycloneDX file carries the components and their versions, which is what turns a broad 'you run this vendor' match into a precise 'this exact build is affected' one.
$ cvetools stack import --sbom sbom.cdx.json$ # each component -> a normalized entity; versions preserved;$ # unmatched/in-house names are reported, not silently droppedThis is how it sits next to a scanner instead of competing with it: your SBOM or scanner export stays the source of truth, and My Stack is the exploitation-watch layer reading from it. You're not maintaining a second inventory — you're feeding the first one into a matcher that fires on exploitation events.
Ask 'am I affected?' from CI — without storing anything
Sometimes I don't want to store an inventory at all — I just want a yes/no in a pipeline. The POST /stack/match endpoint takes a list of components, matches them against the live CVE/KEV/exploit data, and returns the hits without persisting a thing. It's the local-only, opsec-friendly mode: nothing gets stored as a tracked stack.
$ # ad-hoc 'am I affected?' — matches components, stores NOTHING$ curl -s $CVE_TOOLS_BASE/api/v1/stack/match \$ -H "Authorization: Bearer $TOKEN" \$ -d '{"entries":[{"vendor":"apache","product":"log4j"}],"kev_only":true}'$ # returns only the KEV-listed hits; gate a build on a non-empty resultWhat normalization buys you
Every imported name is collapsed to a canonical entity, so nginx, nginx-inc/nginx and f5/nginx all track the same product, and a CVE that lists any of those spellings matches once. In-house or obscure software that doesn't map to a known product stays as an unmatched entry — visible, honest, and ready to match the day the catalog learns it — rather than being quietly thrown away.
The precision payoff is real: apache log4j imported from an SBOM matched CVE-2021-44228 (Log4Shell) as a canonical product, not a vendor guess — so it landed in my act queue with the version context intact, not buried in a firehose of 'everything Apache ever shipped.'
Honest limits
- Normalization has gaps. Niche and in-house names may not resolve yet — they sit unmatched until the catalog covers them.
- Scan reads packages, not running versions of appliances. A host scan sees OS packages well; closed appliances and SaaS you'll still add by name.
- An import is a snapshot. Re-run it on a schedule (a cron on the scan, an SBOM step in CI) or your stack drifts from reality — the same way any inventory does.
What SBOM format do you accept?
sbom.cdx.json). Components and versions are read; the version context is what makes matches precise instead of vendor-wide.Does importing upload my whole inventory to a server?
stack scan and stack import send product names (and versions if present) to build your stored stack. If you don't want to store anything, stack match runs the check ad-hoc and persists nothing — a local-only mode for CI or the privacy-conscious.Can I fail a CI build on an exploited dependency?
POST /stack/match with kev_only:true returns just the KEV-listed hits for a list of components and stores nothing — gate your pipeline on a non-empty result to fail on real exploitation, not just severity.