
The last time I audited a mid-sized Node.js project, I counted 1,412 dependencies. The team had installed exactly 23 of them on purpose. The other 1,389 arrived as transitive dependencies, quietly pulled in by the packages they actually wanted. That gap between what you choose and what you get is where open source supply chain security lives or dies.
Here is the uncomfortable statistic: Sonatype's annual reports have tracked a sustained surge in malicious packages published to public registries, with hundreds of thousands of hostile or compromised components identified across npm, PyPI, and RubyGems in recent years. Attackers no longer need to breach your firewall. They just need one popular package to trust one bad maintainer, and your build server does the rest.
This article is a working practitioner's guide to vetting a package before the install command runs. You'll get a repeatable checklist, a worked example with real numbers, a comparison of scanning tools, and a step-by-step walkthrough you can run today. No theory dumps. Just the process I actually use.
Key Takeaways
- Transitive dependencies are the real risk. You vet 20 packages and inherit 1,000. Audit the whole tree, not the top level.
- Maintainer health beats star count. A package with 40,000 stars and one exhausted maintainer is a single point of failure.
- Pin and lock everything. Use lockfiles, hash pinning, and version ranges you actually understand.
- Automate the boring checks. SCA scanners, SBOMs, and CI gates catch what manual review misses at 2 a.m.
- Typosquatting is cheap for attackers. Verify the exact package name and publisher before every new install.
- Buying vetted software shifts the burden. A reputable marketplace with a clear vendor and support channel removes an entire class of supply chain unknowns.
What "Open Source Supply Chain Security" Actually Means
Your software supply chain is every piece of code that ends up in your running application that you didn't write yourself. That includes direct dependencies, transitive dependencies, build tools, CI plugins, container base images, and even the scripts that run during npm install.
Supply chain security is the practice of verifying that each of those components is what it claims to be, comes from who it claims to come from, and does only what it claims to do. It's a trust problem dressed up as a technical one.
There are four failure modes worth naming clearly:
- Malicious injection. A legitimate package gets a new release with hidden code, usually after a maintainer account is compromised or handed off.
- Typosquatting. An attacker publishes
reqeustshoping you fat-fingerrequests. - Dependency confusion. A public package impersonates your internal private package name and gets pulled in by mistake.
- Abandonment. No malice, just a dead project with unpatched vulnerabilities that quietly rots inside your build.
Most guides obsess over the first one. In my experience, abandonment causes more real-world incidents because it's boring and easy to ignore. If you're evaluating security tooling more broadly, our breakdown of ISO 27001 compliance software for 2026 covers how these controls fit into a formal program.
The Pre-Install Vetting Checklist I Actually Use
Before I add any dependency to a project, it goes through the same gauntlet. This takes about four minutes per package once you've done it a few dozen times. It has saved me from at least three genuinely bad decisions.
1. Confirm the exact name and publisher
Read the package name character by character. Check the publisher or organization. On npm, look at who owns the scope. On PyPI, check the project's verified links back to a real repository. Typosquats die at this step.
2. Check release cadence and recency
Open the release history. A healthy library ships patches within weeks of a CVE disclosure. If the last release was three years ago and the issue tracker has 200 open bugs, treat it as abandoned regardless of popularity.
3. Audit maintainer count and activity
One maintainer is a bus-factor risk and an account-takeover risk. Two or three active maintainers with recent commits is a much healthier signal. Look at whether commits come from real, identifiable humans.
4. Read the install scripts
This is the step almost everyone skips. Packages can run arbitrary code during installation via postinstall hooks. Search the package for install scripts and read them. If a logging library wants to run a shell script on install, that's a red flag.
5. Scan for known vulnerabilities
Run the package and its tree through a software composition analysis (SCA) tool before committing. npm audit, pip-audit, OSV-Scanner, and Trivy all do this. More on choosing between them below.
6. Measure the dependency footprint
A package that pulls in 80 transitive dependencies to do string padding is a liability. Fewer, well-scoped dependencies are almost always safer. Check the full install size and dependency count.
7. Verify the license
Not strictly security, but a copyleft license slipping into a commercial product is its own kind of incident. Confirm the license matches your project's requirements.
A Worked Example: Vetting a New npm Dependency
Let's make this concrete. Say you're building a Node.js API and you want to add date formatting. You're choosing between two candidate packages: a popular all-in-one date library and a smaller, focused alternative.
Here's the actual before-and-after when you run the checklist:
- Candidate A (the big one): 2.1 MB installed, 6 transitive dependencies, last release 8 months ago, 2 active maintainers, no install scripts, MIT licensed, zero known CVEs. Audit clean.
- Candidate B (the tiny one): 41 KB installed, 18 transitive dependencies, last release 2 years ago, 1 maintainer who hasn't committed in 14 months, one
postinstallscript that phones an analytics endpoint, one moderate CVE with no patch available.
On raw size, Candidate B looks leaner. But the vetting process flips the decision entirely. Eighteen transitive dependencies behind a 41 KB package means 18 more trust decisions you can't see. A single dormant maintainer means no one is coming to fix that CVE. And the install-time network call is exactly the behavior malicious packages use to fingerprint your build environment.
The four minutes you spend here changes the outcome. You pick Candidate A, document why in a short note in your dependency log, and move on. That log matters later when someone asks why the choice was made, and it's the difference between a decision and a guess.
Comparing Supply Chain Scanning Tools
You can't vet by hand at scale. The manual checklist is for the packages you're actively deciding on. For everything already in your tree and every future update, you need automation. Here's how the tools I've used in production stack up.
| Tool | Ecosystems | SBOM output | CI integration | Cost | Best for |
|---|---|---|---|---|---|
| OSV-Scanner | Broad (npm, PyPI, Go, more) | Reads SBOMs | Excellent | Free | Lockfile scanning |
| Trivy | Deps + containers + IaC | Yes (CycloneDX/SPDX) | Excellent | Free | All-in-one scanning |
| Dependabot | Many via GitHub | No | Native (GitHub) | Free on GitHub | Automated PR updates |
| Snyk | Broad | Yes | Excellent | Free tier + paid | Fix guidance + reporting |
| Socket | npm, PyPI focus | Partial | Good | Free tier + paid | Behavior/supply-chain risk |
My default stack for most teams: Trivy for broad scanning in CI, OSV-Scanner as a fast lockfile gate, and Dependabot for automated update pull requests. Socket is worth adding when you specifically worry about install-time behavior, because it flags the network calls and shell executions that CVE databases won't. If your concern is the newer wave of AI-assisted tooling in your pipeline, our guide to vetting AI coding agents safely is a useful companion read.
Building a Repeatable Vetting Workflow in CI
Manual discipline evaporates under deadline pressure. The only vetting that survives is the vetting your pipeline enforces automatically. Here's a workflow you can stand up in an afternoon.
- Generate a lockfile and commit it. Use
package-lock.json,poetry.lock, or your ecosystem's equivalent. This freezes exact versions and hashes so builds are reproducible and tamper-evident. - Add an SBOM generation step. Run Trivy or Syft to produce a CycloneDX software bill of materials on every build. This is your inventory. You can't secure what you can't list.
- Run an SCA scan as a required check. Configure OSV-Scanner or Trivy to fail the build on high or critical vulnerabilities. Set the threshold deliberately; failing on every low-severity finding trains people to ignore it.
- Enable dependency update automation. Turn on Dependabot or Renovate to open pull requests for updates. Review them like any other code change, not as rubber-stamp merges.
- Gate new dependencies with a human review. Add a rule that any change to your manifest file requires an explicit approval. This is where your four-minute manual checklist plugs in.
- Log every dependency decision. A simple markdown file recording why each non-obvious package was chosen pays for itself the first time you investigate an incident.
Patch velocity is the metric to watch. If a critical CVE drops and you can't ship a patched build within 48 hours, your workflow has a gap. Our comparison of Cover image: Carriage of Cargoes & Containers Sub-Committee (CCC 4) by imo.un, licensed under BY 2.0 via Openverse.








