DEV Community

Tony Metzidis
Tony Metzidis

Posted on

How to Finally (and Iteratively) Kill Every Last 'npm audit'

Let’s be honest: npm audit is a necessary evil. If you manage a monorepo, a large scale-backend microservice architecture, or even just have fifty toy projects in your /dev folder, you know the dread. You run an audit, get 400 vulnerabilities, and standard npm audit fix just breaks things.

The real problem isn't fixing the vulnerability; the problem is the management of the vulnerabilities.

Manually cd-ing into 30 different directories, running the audit, deciphering the output, deciding which package.json to edit, and then doing the work? That's an efficient way to burn out an afternoon.

Here is the tool you didn’t know you needed.

The Problem: Multi-Directory Triage

You are working across multiple contexts (multiple directories). You have dozens of tasks:

  1. Find the package.json.
  2. Navigate to that folder.
  3. Run the audit.
  4. Decide if it’s a manual fix (Mocha 11x, looking at you) or an audit fix --force candidate.
  5. Mark it done and move on.

The standard Unix toolbox doesn’t have a built-in interactive "loop through directories and run commands, pausing for input" command.

The Solution: fzf as an Interactive Runner

/home/tonymet/dev/
> api-gateway-service                                                  │ Path: ./api-gateway-service
  auth-provider                                                       │ 
  legacy-reporting-tool                                               │ 🔒 npm audit report
  frontend-dashboard                                                  │ 
  shared-auth-library                                                 │ 📉 Low             1
                                                                      │ 📈 High            3
                                                                      │ 💥 Critical        1
                                                                      │ 
                                                                      │ Found 5 vulnerabilities in 890 scanned packages.
                                                                      │ 3 vulnerabilities require manual review.
                                                                      │ 
                                                                      │ Run `npm audit fix` to fix 2 of them.
                                                                      │ 
                                                                      │ =========================================================
                                                                      │ Critical: Remote Code Execution
                                                                      │ Package: serialize-javascript
                                                                      │ Dependency of: mocha [dev]
                                                                      │ Path: mocha > serialize-javascript
                                                                      │ More info: https://github.com/advisories/GHSA-hxcc-f52p
                                                                      │ 
                                                                      │ =========================================================
                                                                      │ High: Prototype Pollution
                                                                      │ ... (rest of audit output scrolled)
[5/5] -----------------------------------------------------------------│
> _
Enter fullscreen mode Exit fullscreen mode

The solution is combining the powerhouse finder fzf with some standard find commands.

We are going to use fzf not just to select a file, but as an interactive dashboard.

The One Command to Rule Them All

Here is the command (Unix/Linux/macOS):

find . -name "package.json" -not -path "*/node_modules/*" \
| fzf --preview 'echo $(dirname {}) && cd $(dirname {}) && npm audit' \
      --preview-window=right:80%
Enter fullscreen mode Exit fullscreen mode

What is happening here?

This looks complicated, but it's remarkably elegant:

  1. find . -name "package.json" -not -path "*/node_modules/*": This is our discovery engine. It searches the entire directory tree (.) for package.json files, but critically skips anything inside a node_modules folder (we don’t want to audit dependencies' dependencies, only the root projects). This feeds a clean list of file paths to the next command.
  2. | fzf: We pipe that list into fzf, the interactive finder. This creates the interface.
  3. --preview '...': This is the magic. When you highlight a path in fzf, this entire script runs in the side-pane:
    • echo $(dirname {}): Shows you the clean path to the directory containing the package.json.
    • cd $(dirname {}): Temporarily navigates the preview process into that directory.
    • npm audit: Executes the audit specifically inside that folder.
  4. --preview-window=right:80%: We give the preview window 80% of the screen. Why? Because npm audit output is verbose, and you need to be able to read the specifics of the dependency tree to make triage decisions.

How to Use the Interface

When you run this command, your terminal transforms:

  • Left Side: A list of every project in your /dev folder that has a package.json.
  • Right Side: The live output of npm audit for whichever project you highlight.

Now you can triage! Use the up and down arrow keys to quickly review the security status of every project without leaving the dashboard.

Actually "Doing Work"

The standard configuration above is a read-only view. It lets you quickly see where the major problems are (e.g., "Oh, all these old 2022 projects need Mocha 12").

If you want to actually execute fixes from within the interface, we need to bind a key:

find . -name "package.json" -not -path "*/node_modules/*" \
| fzf --preview 'echo $(dirname {}) && cd $(dirname {}) && cat package.json' \
      --preview-window=right:80% \
      --bind 'enter:execute(cd $(dirname {}) && npm audit fix && echo -n DONE | read)+down'
Enter fullscreen mode Exit fullscreen mode

What this version does:

  • Default Preview: Shows package.json (running audit constantly in preview can be slow).
  • Enter (Binding): When you hit Enter:
    1. It runs npm audit fix in that folder.
    2. It uses echo -n DONE | read to pause the interface (pressing any key resumes).
    3. +down: After you resume, it automatically moves the selection to the next directory on the list.

It mimics the exact "triage and advance" workflow of an interactive rebase.

When the interface is painless, you are more likely to run it. When the effort of auditing 100 directories is reduced to "holding down the down arrow," security gets addressed.

Top comments (0)