vulnix
2 min read
Vulnerability scanner for the Nix Store. It walks the derivations reachable from a given path (a system, a build output, or a .drv), extracts each package's name and version, and matches them against CVE entries from NIST's National Vulnerability Database (NVD).
Because Nix pins every dependency to an exact store path, vulnix can audit the complete transitive closure of what you actually run — not just what a package manifest claims.
How it works
1. Fetches the NVD CVE feeds and keeps a local cache (first run downloads a lot).
2. Resolves the closure of the target path via nix-store, collecting every .drv.
3. Parses derivation names into name + version and matches them against CVEs using heuristics (direct match, lowercasing, _↔- substitution).
4. Applies whitelists and CVE-patch detection to drop false positives.
5. Reports affected packages with CVE IDs, NVD links and CVSSv3 scores.
Usage
bash
# audit the running NixOS system
vulnix --system
# audit a build output and its full closure
vulnix result/
# audit specific derivations WITHOUT pulling in their dependencies
vulnix -R /nix/store/*.drv
# machine-readable output (for CI / dashboards)
vulnix --json --system
Make sure nix-store is on PATH, the store db (/nix/var/nix/db) is readable, and a sane locale is set (export LANG=C.UTF-8).
Key flags
| Flag | Description |
|---|---|
--system | scan the active system configuration |
-R | don't compute the transitive closure (scan only given paths) |
--json | emit JSON instead of the human-readable report |
-w FILE/URL | load whitelist(s) from a local file or HTTP URL |
-G | don't fetch/update the NVD cache (use local only) |
-V | increase verbosity |
Exit code is non-zero when vulnerabilities are found, so it drops straight into CI.
Whitelisting
False positives and accepted risks are suppressed via TOML whitelists, loaded with -w:
toml
["ffmpeg-3.4.2"]
cve = ["CVE-2018-6912", "CVE-2018-7557"]
until = "2026-05-01" # rule auto-expires on this date
issue_url = "https://issues.example.com/29952"
comment = "patched downstream, tracking upstream fix"
• A bare [pkgname] table matches any version; [pkgname-version] pins one.
• cve = [...] scopes the rule to specific CVEs; omit it to whitelist the whole package.
• until makes rules expire so they don't rot silently.
CVE patch detection
If a derivation applies a patch whose filename contains a CVE id (e.g. CVE-2018-6951.patch), vulnix recognises it as fixed and suppresses that CVE automatically — no whitelist entry needed.