Skip to main content Skip to page footer

Introducing vulnix - a vulnerability scanner for NixOS

Erstellt von Maksim Bronsky | | Blog

As we are in the preliminary phase of releasing our new NixOS based platform as a stable, security related topics gain further momentum. The question of how and when a system is affected by a security flaw is certainly not only related to our use-case, we suspect this to be of importance for some.

Just a glance over the nixpkgs-issue tracker and the mailinglist shows:

At the moment the discussion is still at its infancy, which means it's mostly discussing about the needs and ideas of how to cope with CVEs, or monitoring in general.  Improving package QA and so forth. Phreedom's nixpkgs-monitor, one of the first  to show some working code is quiet a comprehensive tool. Downloading CVE xmls matching them via a heuristic with the nix derivations names of nixpkgs. All the results will be saved into a sqlite database and from there on  it can fuel a web frontend like  This is fine and swell from a package maintainers perspective, who takes the extra step to his/her maintenance schedule, but there is a catch  it's made for humans. This is where vulnix comes into play. It reverses the nixpkgs-monitor approach answering the question, which of my current active garbage collecting roots is affected by a known CVE. Indiviually(!) for every running system. At first we ask the nix-store to show us the derivations of the live gc-roots, we then take these derivation files (*.drv) and mock them with Derive Class as they happen to fit the Python syntax ;-). As a result we get an object, carrying  the derivations properties like name, builder etc and a set of methods to check them against (potential) vulnerabilities.  This is what the store.update() method is for.

store = Store ()

Then we collect the vulnerabilities in two steps. nvd.update() downloads the gzip'ed nvdcve-files from NIST. In nvd.parse() we translate the XML document to the Common Platform Enumeration (cpe) format,  a naming scheme used by NIST to structure affected software products in categories like vendor, version and the likes. This helps to match derivations and vulnerabilities.

nvd = NVD () 
nvd.update () 
nvd.parse ()

As the naming scheme in the CVEs does not necessarily needs to fit the bill of NixOS derivations, and the match atm is solely decided by name and optionally version we had the need to exclude some issues manually. Providing a yaml file (whitelist.yaml). As an example we encountered the access derivation in Nix which lead to a match with Microft Access related entries.

whitelist = WhiteList()


This is taken from our unit test. The  options will be extended in the process ( we are experimenting with state flags, to produce more subtle check informations).  All the properties work as filter and will be linked together, you may exclude a whole CVE id or specify a certain package in a specific version, where the issues is known to you or whatever good reason you come up with. We found it came in handy to either match properties of the derivation (name, version) or the CVE related ones (vendor, product).

$ cat src/vulnix/tests/whitelist.yaml
  cve: CVE-2015-2503
    microsoft access, accidentally matching the 'access' derivation

  name: libxslt

  cve: CVE-2015-7696
  name: unzip

  derivation: libxslt
  version: '2.0'

  vendor: microsoft
  product: access



$ hg clone
$ cd ./vulnix
$ ./


Disclaimer: As of today we still tweak the heuristics and the output format and thus haven't done too much for the commandline invocation.

$ bin/vulnix


This is a pick running on my Mac, where we get the package which is (might be) affected (top left), then the matching and the referring derivation. It's actually quite self explanatory. We intend to use this format for the verbose output field of our sensu infrastructure.



Referenced by:


Used by: