🌏 中文版
TL;DR
Upgrading package.json doesn’t mean your Docker image is clean. Vulnerability scan results for Node.js images typically fall into at least two categories: your project’s own packages, and packages bundled with npm inside the base image. The glob, minimatch, tar, and diff hits in this scan weren’t coming from the app’s node_modules at all — they were brought in by npm@10.9.4, which is bundled inside node:22-alpine. The fix isn’t just updating package.json; you also need to upgrade npm inside the image to 11.11.1.
Bottom Line First
When you hit a Node.js image vulnerability scan, don’t immediately suspect the lockfile. Work through this order first:
- Check the app dependency tree
- Then check npm’s own global dependency tree inside the container
- Only then decide whether to update
package.json/ the lockfile, or theDockerfile
This quickly tells you whether you’re dealing with an application package issue or a base image toolchain issue.
Context
While cleaning up vulnerability scan results for a Node.js project, I upgraded everything possible in package.json and yarn.lock — both runtime and dev dependencies.
The project side looked clean:
package.jsonupdated to newer dependency versionsyarn.lockregenerated- No old versions of the flagged
diff,glob, ortarpackages visible in the local dependency tree
But after rebuilding the Docker image and scanning again, the same findings kept appearing:
diff@5.2.0glob@10.4.5minimatch@9.0.5tar@6.2.1tar@7.4.3
The Problem
It looked like “the packages just didn’t upgrade” — but the project dependency tree didn’t match what the image scanner was finding.
If you only stare at package.json and yarn.lock, it’s easy to get stuck here:
npm ls diff glob minimatch tar --all --depth=6
Running this in the project shows very few results, and versions that don’t match what the vulnerability report listed — yet the image scan is clearly reporting that those vulnerable versions exist inside the container.
Investigation
In this kind of situation, I now always split the investigation into two layers.
Layer 1 — app packages:
- Check
package.json - Check
yarn.lock - Check the actual dependency tree in
node_modules
Layer 2 — npm’s own package tree:
- Check the Node / npm version in the base image
- Inspect the global npm dependency tree directly inside the container
The base image used here was:
FROM node:22-alpine
Running this inside the container made things clear immediately:
docker run --rm node:22-alpine sh -lc "node -v && npm -v && npm ls -g diff glob minimatch tar --all --depth=6 || true"
The output matched the vulnerability report exactly:
v22.22.1
10.9.4
/usr/local/lib
└─┬ npm@10.9.4
├── glob@10.4.5
├── minimatch@9.0.5
├── tar@6.2.1
├── tar@7.4.3
└── diff@5.2.0
The scan hits weren’t from the app’s installed dependencies at all — they were coming from the built-in npm package tree inside the base image.
Fix
Since the root cause is npm itself, upgrading project dependencies alone isn’t enough. You also need to upgrade npm inside the image.
Here’s what was added to the Dockerfile:
FROM node:22-alpine
RUN apk update && apk upgrade --available && sync
RUN apk add --update ca-certificates openssl && update-ca-certificates
# Upgrade npm to fix bundled tar CVEs (tar@6.x bundled in npm@10, fixed in npm@11.11.1+)
RUN npm install -g npm@11.11.1
After upgrading, verify it worked:
docker run --rm <your-image> sh -lc "npm -v && npm ls -g tar --depth=2 || true"
You should see something like:
11.11.1
/usr/local/lib
└─┬ npm@11.11.1
└── tar@7.5.11
At this point, the old tar@6.x is gone from the image, and the vulnerability findings will actually disappear.
Why This Happens
Docker image vulnerability scanners don’t just scan your application directory — they scan the entire filesystem for installed packages.
For Node.js images, there are at least two common sources:
-
Project dependencies From
package.json/ lockfile /node_modules -
Base image toolchain Things like npm itself, and npm’s internal dependencies:
glob,minimatch,tar,diff
So seeing tar in the scan doesn’t necessarily mean some library in your project brought it in. It might just be npm’s own internal dependency it uses to handle package archives.
Without separating these two categories upfront, you’ll likely run into one of two false assumptions:
- The app packages are already upgraded, but you keep suspecting the lockfile isn’t up to date
- The problem is in the base image, but you keep blindly adding overrides / resolutions to
package.json
Quick Triage Flow
Next time I hit something similar, here’s the order I’ll follow:
- Check
package.jsonand the lockfile — confirm whether the project is actually pinned to an old version - Run the app dependency tree — confirm whether the issue is coming from
node_modules - Run
npm ls -g ...directly inside the base image or target image - If the hit is from npm’s built-in dependencies, fix the
Dockerfile - If the hit is from an app dependency, then go back and update the package version or lockfile
Key Takeaway
When reviewing Node.js Docker image vulnerability scans, ask yourself first: Is this vulnerability in an app package, or in npm’s own packages? Identify the source before deciding whether to fix package.json or the Dockerfile. It’s faster, and you’re much less likely to fix the wrong thing.
References
Loading...