Node.js dependency scanning with Trivy isn’t just about finding vulnerabilities; it’s about understanding the hidden risks in your transitive dependencies.
Let’s see Trivy in action. Imagine you have a simple Node.js project with a package.json and a yarn.lock (or package-lock.json).
// package.json
{
"name": "my-node-app",
"version": "1.0.0",
"dependencies": {
"express": "^4.17.1",
"lodash": "^4.17.21"
}
}
# yarn.lock (snippet)
lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#..."
integrity sha512-v2a3e554..."
Now, run Trivy against this project directory:
trivy fs .
Trivy will dive into your node_modules (or, more efficiently, use your lock file) and analyze the declared dependencies. It doesn’t just look at express and lodash. It recursively examines their dependencies, and their dependencies, and so on, building a complete graph. For each package in this graph, Trivy queries its vulnerability database.
The output might look something like this:
my-node-app (Node.js)
====================
Total: 2 vulnerabilities (2 moderate)
┌─────────────┬─────────────┬─────────────┬───────────┬────────────────────────────────────────────────────────────┐
│ Library │ Vulnerability │ Installed │ Fixed │ Advisory │
├─────────────┬─────────────┬─────────────┬───────────┬────────────────────────────────────────────────────────────┤
│ lodash │ GHSA-47qg-252g-6h2x │ 4.17.21 │ 4.17.21+ │ Prototype Pollution (Moderate) │
│ │ │ │ │ https://github.com/advisories/GHSA-47qg-252g-6h2x │
│ │ │ │ │ Description: Versions of lodash prior to 4.17.21 are affected │
│ │ │ │ │ by Prototype Pollution. This vulnerability occurs when... │
│ express │ CVE-2023-45134 │ 4.17.1 │ 4.18.2 │ Express.js Denial-of-Service Vulnerability │
│ │ │ │ │ https://github.com/advisories/GHSA-xxxx-xxxx-xxxx │
│ │ │ │ │ Description: A flaw in Express.js allows a remote attacker │
│ │ │ │ │ to cause a denial-of-service... │
└─────────────┴─────────────┴─────────────┴───────────┴────────────────────────────────────────────────────────────┘
What Trivy is doing under the hood is parsing your package.json and lock file (yarn.lock or package-lock.json). It builds an internal representation of your dependency tree, including the exact versions of every package installed. For each package, it then checks its Common Vulnerabilities and Exposures (CVE) database, matching the package name and version against known vulnerabilities. The magic is in the completeness of the tree traversal and the breadth of the CVE data.
The problem this solves is the "dependency hell" and the hidden risk of transitive vulnerabilities. You might update lodash to the latest version, thinking you’re safe, but express might be pinning an older, vulnerable version of lodash that you also need to address. Trivy unearths these indirect risks.
The levers you control are primarily your dependency versions. Trivy’s output guides you on which specific packages, and which versions, need updating. You can also configure Trivy to ignore certain vulnerabilities or specific packages if you have a strong justification.
The most surprising thing about Node.js dependency scanning is how often vulnerabilities hide in packages you don’t directly import. You might have a security-conscious setup, carefully vetting your direct dependencies, only to find that a seemingly innocuous package you installed years ago, which is a dependency of a dependency of a dependency, now has a critical CVE. Trivy’s recursive analysis is key here; it doesn’t stop at your top-level dependencies or devDependencies.
When you fix the vulnerabilities reported by Trivy, you’ll likely need to run npm update or yarn upgrade to update the affected packages. After updating, you’ll re-run Trivy to confirm the vulnerabilities are gone. The next logical step is to integrate this scanning into your CI/CD pipeline to catch regressions.