Flake-agnostic vulnerability scanning for Nix flakes, packaged as both a reusable GitHub Action and a local CLI.
flakevuln generalizes
ghafscan: keep the proven clone,
re-lock against different nixpkgs pins, then diff the vulnerability sets
engine; drop the Ghaf-specific assumptions and commit-back state model; render
the results as a GitHub Actions Step Summary and a detailed local markdown
report.
- Scans one or more flake outputs from a checked-out repository or a remote flakeref.
- Compares the committed lock state against a re-locked baseline for a chosen
input, defaulting to
nixpkgs. - Optionally adds a third scan against an explicit unstable input such as
github:NixOS/nixpkgs/nixos-unstable. - Writes machine-readable findings plus markdown reports.
- Reuses the same engine locally and in GitHub Actions.
- Persists
grype,vulnix,sbomnixHTTP cache data, and prior-run baseline findings across workflow runs.
The composite action installs Nix, builds flakevuln, runs an untrusted scan
phase, then renders the report in a trusted phase.
name: flakevuln
on:
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: tiiuae/flakevuln@<commit-sha>
with:
targets: |
packages.x86_64-linux.defaultPrefer pinning the action to a full commit SHA in production workflows.
name: flakevuln
on:
workflow_dispatch:
schedule:
- cron: "17 3 * * 1"
permissions:
contents: read
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: tiiuae/flakevuln@<commit-sha>
with:
targets: |
packages.x86_64-linux.default
devShells.x86_64-linux.default
unstable-ref: github:NixOS/nixpkgs/nixos-unstable
whitelist: .github/flakevuln/manual_analysis.csv
nixprs: true
nixtracker: true
cachix-caches: nix-community my-orgname: flakevuln
on:
pull_request:
permissions:
contents: read
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: tiiuae/flakevuln@<commit-sha>
with:
flakeref: ./services/api
targets: |
packages.x86_64-linux.defaultFor an in-repository example that uses the checked-out action source directly, see example-scan.yml.
| Input | Required | Default | Description |
|---|---|---|---|
targets |
yes | - | Newline-delimited flake outputs to scan. |
flakeref |
no | . |
Flake to scan. . means the checked-out workspace root; a subdirectory also works. |
input-name |
no | nixpkgs |
Re-lockable input to diff against. |
unstable-ref |
no | "" |
Optional third scan target, typically github:NixOS/nixpkgs/nixos-unstable. |
whitelist |
no | "" |
Path to a suppressions CSV in the caller repository. |
nixprs |
no | false |
Enable best-effort nixpkgs PR enrichment during report rendering. |
nixtracker |
no | false |
Enable best-effort Nixpkgs security tracker enrichment during report rendering. |
token |
no | "" |
Optional token for nixprs; when empty, the trusted report step falls back to github.token. |
cachix-caches |
no | "" |
Space-delimited Cachix cache names to add as read-only substituters. |
- Supported runners: Linux runners. The action is designed around
cachix/install-nix-action, so macOS may work, but this repository currently validates releases on Linux. - Required workflow permissions:
contents: readis sufficient for the normal checkout-and-scan flow. - Security model: the untrusted
scanphase runs withoutGH_TOKEN; optional GitHub-authenticated enrichment happens later in the trustedreportphase. - Action outputs: none. The action writes its operator-facing result to the GitHub Step Summary.
- Baseline diffing: the action persists a prior findings set keyed by flakeref,
targets, and
input-name, then reports what changed since the last successful run for that same scope.
The action restores the newest matching cache entry from earlier runs and saves fresh state for the next run. It persists:
- the
grypedatabase - the
vulnixdatabase sbomnix's shared HTTP cache for OSV, repology, and optionalnixprs/nixtrackerlookups- the previous-run findings baseline used for "since last run" sections
- Nix with
nix-commandandflakesenabled - Linux
GH_TOKENin the environment if you want higher GitHub API rate limits for--nixprslookups; without it,flakevulnfalls back to anonymous best-effort queries
Run against the current checkout:
nix run .#flakevuln -- local packages.x86_64-linux.defaultBy default, local writes outputs under .flakevuln/:
findings.jsonreport/README.mdreport/*.mdfor per-target detail pages
Scan a remote flake by embedding the target in the flakeref:
nix run .#flakevuln -- local \
-f 'github:nix-community/poetry2nix#packages.x86_64-linux.default'When --flakeref already includes a #target fragment, you can omit the
positional target arguments.
Scan a flake from a local subdirectory:
nix run .#flakevuln -- local \
-f ./services/api \
packages.x86_64-linux.defaultScan multiple outputs from the current checkout:
nix run .#flakevuln -- local \
packages.x86_64-linux.default \
devShells.x86_64-linux.defaultWrite outputs somewhere else:
nix run .#flakevuln -- local \
-o out/flakevuln \
packages.x86_64-linux.defaultRun the optional unstable comparison:
nix run .#flakevuln -- local \
--unstable-ref github:NixOS/nixpkgs/nixos-unstable \
packages.x86_64-linux.defaultUse a suppressions CSV:
nix run .#flakevuln -- local \
--whitelist .github/flakevuln/manual_analysis.csv \
packages.x86_64-linux.defaultEnable best-effort nixprs enrichment:
nix run .#flakevuln -- local \
--nixprs \
packages.x86_64-linux.defaultEnable best-effort Nixpkgs security tracker enrichment:
nix run .#flakevuln -- local \
--nixtracker \
packages.x86_64-linux.defaultIf the flake input you want to re-lock is not named nixpkgs, set it
explicitly:
nix run .#flakevuln -- local \
--input-name my-nixpkgs \
packages.x86_64-linux.defaultUse the low-level subcommands when you want to materialize findings first and render reports later:
nix run .#flakevuln -- scan \
--flakeref . \
--target packages.x86_64-linux.default \
--findings findings.json
nix run .#flakevuln -- report \
--findings findings.json \
--outdir report \
--nixprsThe whitelist action input and the --whitelist CLI flag both point to a CSV
that you keep in your own repository. This repository's dogfood scan keeps its
triage in
.github/flakevuln/manual_analysis.csv.
Prefer explicit True and False values in the whitelist column:
Truesuppresses a matching finding.Falsekeeps the finding active and only records the accompanying comment.