Vulnerability Inventory across Profiles and Images
Vulnerability Inventory across Profiles and Images
Thesis
A clean nixos-rebuild does not mean every closure you run is patched. User profiles, old generations, nix-shell GC roots, and container images keep old store paths alive. Inventory must walk those roots, not only the booted system.
Mental model
live software = union of closures reachable from:
- current system generation
- previous generations (until GC)
- per-user profiles (~/.nix-profile, home-manager)
- explicit GC roots (docker layers, result symlinks)
- ephemeral shells pinned by direnv / nix-direnv
CVE scanners that only look at /run/current-system under-report.
Worked example
Docs-based inventory checklist (nix absent here):
# booted system
readlink -f /run/current-system
# generations still rooted
nix-env --list-generations -p /nix/var/nix/profiles/system
# user profile
nix profile list # or nix-env -q
# GC roots that surprise you
ls -l /nix/var/nix/gcroots
# container image built with dockerTools / nix2container
# → scan the image's closure, not just the hostWire a scanner (e.g. vulnix, VEX/NixOS VEX workflows, or SBOM export) against each root class. Delete stale generations and result links when patches land.
Trap
“We rebuilt yesterday” as a security statement. Old generations remain bootable and runnable. CI images cached on a registry may pin a vulnerable bash for months.
Boring rule
Track roots explicitly, GC on a schedule, and fail deploys when a scanner finds a CVE in any still-rooted closure you ship — not only in current-system.
Try this
- List GC roots before/after removing a
resultsymlink. - Compare
nix path-info -r /run/current-systemvs a home-manager profile. - Export an SBOM for a
dockerToolsimage and scan it offline.
Sources
- Nix manual: garbage collection / profiles
- NixOS VEX / vulnerability tracking discussions in nixpkgs
- Software supply-chain SBOM practices for Nix closures