VULNIX(1)

πŸ“¦
version 1.12.5 Β· 2 versions
, in nixpkgs unstable

πŸ’… VULNIX(1) β€” the vulnix manual, bestie edition ✨

okay so you're reading vulnix(1), the User Commands page for everybody's favorite Nix(OS) vulnerability scanner. grab a snack, this is gonna be good πŸ“

✨ NAME ✨

vulnix β€” a Nix(OS) vulnerability scanner. that's it, that's the vibe check πŸ‘‘

🌸 SYNOPSIS 🌸

vulnix [OPTIONS] --system

vulnix [OPTIONS] PATH ...

πŸ¦‹ DESCRIPTION πŸ¦‹

so here's the whole thing: vulnix goes digging through Nix derivations and their transitive closure, hunting for vulnerable software versions as published in the NIST NVD. when it finds affected derivations it reports them, together with the matching CVE identifiers. no cap, that's the entire point πŸ’–

the last argument is where the search starts, and it can be any one of these:

  • a derivation, like /nix/store/0123456789-program-1.0.drv
  • an output file in the Nix store that has a known deriver
  • a link into the Nix store, like result

before the actual scanning begins, parts of the NIST NVD database get fetched and parsed. that database copy is cached between vulnix invocations and gets checked at regular intervals, so it's not re-downloading the world every time 🌈

also? vulnix uses whitelists to mask certain combinations of packages and CVEs that straight up should not be reported. iconic behavior honestly.


πŸ’… OPTIONS πŸ’…

  • -g, --guest=PATH β€” scan a foreign Nix installation rooted at PATH. heads up bestie: paths you pass as positional arguments or with --profile have to be absolute paths as seen inside the guest, like /nix/store/... or /nix/var/nix/profiles/default β€” they are not host paths. and --system / --gc-roots likewise inspect the guest installation. 🫢
  • -S, --system β€” scans the current system, defined as the transitive closure of /run/current-system. the classic.
  • -G, --gc-roots β€” scans all active garbage collection roots. ngl this one is of limited use, because the scan will include all old system generations. you've been warned πŸ’€
  • -p, --profile=PATH β€” scan a nix profile (eg: /nix/var/nix/profiles/per-user/$USER/profile, ~/.nix-profile). these are typically created with nix-env -i or nix profile install β€” but not nix build --profile, which creates normal store paths that don't need this special handling. subtle but important ✨
  • -f, --from-file=FILE β€” scans derivations read from a file. expects one derivation path like /nix/store/*.drv per line. super useful together with -R/--no-requisites, which means that exactly the specified derivations will be scanned πŸŽ€
  • -w, --whitelist=FILE | URL β€” loads a whitelist from the specified local path or URL. check vulnix-whitelist(5) for the whitelist syntax explanation. and no stress: it is not an error if the path/URL does not exist. this option can be given multiple times (stack 'em, queen) πŸ’œ
  • -W, --write-whitelist=FILE β€” writes a new copy of the whitelist containing all reported vulnerable package versions in addition to existing whitelist entries (the ones loaded with -w). use it to evolve your whitelists so every vulnerable version gets reported exactly once. note: expired whitelist entries (like ones where the date set with the until option has passed) will not be written into the new whitelist πŸ™ˆ
  • -r, --requisites / -R, --no-requisites β€” decides whether the transitive closure of the specified paths gets computed and scanned, or only the given pathnames. defaults to --requisites. the whole "closure or nah" question 🌸
  • -c, --cache-dir=DIRECTORY β€” puts cached NVD entries into DIRECTORY. the directory gets created if it doesn't exist. defaults to ~/.cache/vulnix ⭐
  • -m, --mirror=URL β€” fetches NIST NVD updates from URL. defaults to https://nvd.nist.gov/feeds/json/cve/1.1/ πŸ”₯
  • -j, --json β€” outputs affected package versions as a JSON document. see JSON output below πŸ‘‡
  • -s, --show-whitelisted β€” shows whitelisted results in addition to regular (non-whitelisted) results. iykyk 🧚
  • -v, --verbose β€” prints additional info on stderr, including NVD updates, derivation paths, and clickable links to CVE advisories. may be given twice for an extra level of debugging information. double it and give it to the next person 😭
  • -V, --version β€” prints program version and exits πŸ’–
  • --help β€” prints options summary and exits 🌈

πŸ‘‘ EXIT STATUS πŸ‘‘

the exit statuses are compatible with the Nagios plugin development guidelines, https://nagios-plugins.org/doc/guidelines.html β€” which means you can drop this straight into the majority of monitoring systems. slay for CI.

  • vulnix exits 0 if no vulnerabilities are found πŸ‘
  • if all of the shown vulnerabilities are whitelisted, it exits 1
  • otherwise, found vulnerabilities lead to exit status 2
  • exit status 3 indicates an error condition πŸ’€
⚠️ note that exit status 1 may never occur if the --show-whitelisted option is not given. literally cannot happen. plot twist.

πŸŽ€ ENVIRONMENT πŸŽ€

these environment variables affect vulnix, bestie:

  • HOME β€” determines the default cache directory.
  • PATH β€” used to invoke up low-level Nix utilities like nix-store.

🫢 FILES 🫢

vulnix maintains a cache dir located at ~/.cache/vulnix by default.

the Nix store is assumed to be under /nix/store. this pathname is hardcoded β€” no, you can't change it, don't ask πŸ™ˆ


πŸ’€ NOTES πŸ’€

Patch detection

vulnix tries to detect patches for specific CVEs, and these get automatically excluded from reports. the way that works: the patches field of each derivation is scanned for names containing CVE identifiers. if a single patch fixes multiple vulnerabilities, all the relevant CVE identifiers should go in the patch name, separated by arbitrary non-numerical characters. see EXAMPLES below ✨

JSON output

when invoked with --json, a JSON document consisting of a list of dicts is written to stdout. each list item is an affected derivation and contains these keys:

  • name β€” package name and version
  • pname β€” package name without version
  • version β€” version only
  • affected_by β€” list of applicable CVE identifiers
  • whitelisted β€” list of CVE identifiers which are masked by whitelist entries
  • derivation β€” pathname of the scanned derivation file
  • cvssv3_basescore β€” dict of CVSS v3 impact base scores for each CVE found

😭 BUGS 😭

invoking vulnix with an empty cache directory can take quite a while, since it needs to download and process NIST NVD archives of the last 5 years. once initialized, only changed entries get fetched. so like… go get a beverage β˜•

also the cache directory grows slowly but steadily, as there are new CVE advisories added on an ongoing basis. it's not a bug it's a lifestyle 🌱

🧚 COMPATIBILITY 🧚

vulnix is known to parse derivation files created by Nix versions up to 2.3.


πŸ”₯ EXAMPLES πŸ”₯

Is my NixOS system vulnerable?

vulnix --system

Scan the output of nix-build(1) for dependencies with security advisories:

nix-build ... -o result
vulnix result

Report advisories for a derivation and its transitive closure as a structured JSON document:

vulnix -j /nix/store/cm0lrdrf6crb5v38iyygfsbzvivpmh6w-python3-3.6.4.drv

Report all advisories affecting the NixOS base install, whitelisting formerly known vulnerabilities and creating an updated whitelist (a.k.a. vulnerability roundup):

nix-build -I nixpkgs=. nixos/release-combined.nix
vulnix -j \
  -w https://raw.githubusercontent.com/ckauhaus/nixos-vulnerability-roundup/master/whitelists/master.toml \
  -W whitelist-master-new.toml \
  result

An excerpt from a derivation source that applies a patch against CVE-2018-9055. note the name attribute, which contains a CVE identifier:

patches = [
  (fetchpatch {
    name = "CVE-2018-9055.patch";
    url = http://paste.opensuse.org/view/raw/330751ce;
    sha256 = "0m798m6c4v9yyhql7x684j5kppcm6884n1rrb9ljz8p9aqq2jqnm";
  })
];

if the patch fixes two vulnerabilities, it could be named CVE-2018-9055+CVE-2018-9600.patch, for example. see? told you πŸ’…


🌈 SEE ALSO 🌈

vulnix-whitelist(5), nix-store(1), nix-build(1), NIST NVD https://nvd.nist.gov, Nix https://nixos.org/nix/


and that's the page!! πŸ’– mwah 🫢

this has been Version 1.12.5, dated January 1980 (yes really, the copyright date said January 1980, we don't question the icons) β€” VULNIX(1), out. βœ¨πŸŽ€

πŸ“¦ where this page comes from