You would not hand your AWS keys to a stranger on the internet. But every time you run npm install some-package, you are doing something eerily close. The Axios compromise on April 1, 2026, dropped a remote access trojan into one of the most popular HTTP libraries in the JavaScript ecosystem. If your lockfile auto-updated, you might already be running it.
Here is the checklist we run at Fordel before any dependency enters our projects.
How do you verify a package is what it claims to be?
1. Check the package publisher against the maintainer. Go to the npm registry page and verify who published the latest version. If the publisher changed recently — especially from a well-known maintainer to a new account — stop. The Axios attack worked because malicious versions were published by a compromised maintainer account. Run npm view <package> maintainers and compare against the GitHub repo CODEOWNERS or contributors list.
2. Compare the published tarball to the source repo. What ships on npm does not have to match what is on GitHub. Run npm pack <package> and diff the contents against the tagged release on GitHub. Supply chain attacks frequently inject code only into the published artifact, keeping the source repo clean to avoid detection. If the build output diverges from what you can reproduce locally, that is your signal.
3. Verify the version matches a tagged release. Legitimate packages tag their releases on GitHub. If npm shows version 2.4.1 but the GitHub repo has no corresponding tag, ask why. Malicious actors publish versions that exist only on the registry, hoping nobody checks the source. This takes 30 seconds on the GitHub releases page.
What does the package actually do at install time?
4. Read the install scripts before installing. Run npm show <package> scripts or check package.json for preinstall, install, and postinstall hooks. These execute arbitrary code the moment you install. The ua-parser-js compromise in 2021 used a postinstall script to drop a cryptominer. If a library that parses URLs needs a postinstall script, something is wrong. Consider using --ignore-scripts for the initial install and testing manually.
5. Audit the dependency tree, not just the package. A clean top-level package with a compromised transitive dependency is just as dangerous. Run npm audit before you install, and check the transitive tree with npm ls --all <package>. The event-stream attack in 2018 hid in a flatmap-stream dependency three levels deep. Your exposure is the full tree, not just the root.
Is the project actually maintained?
6. Check the last commit date and issue response time. A package with no commits in 18 months is not stable — it is abandoned. Open the GitHub repo and look at the last commit date, open issue count, and how quickly maintainers respond. An abandoned package will not get a CVE patched. Use the GitHub API or just eyeball the pulse page. If the last meaningful commit predates your current Node version, find an alternative.
7. Look at the bus factor. If one person has all the commit access, all the npm publish rights, and all the institutional knowledge, you are one compromised laptop away from a supply chain incident. Check the contributors graph. Packages maintained by a foundation or a team of three or more are meaningfully safer than solo-maintainer projects, especially for anything touching auth, crypto, or HTTP.
How do you evaluate the security posture?
8. Run a vulnerability scan before adoption. Use npm audit, Snyk, or Socket.dev to check for known CVEs in the package and its dependencies. Do not just check — read the actual advisories. A high-severity CVE in a code path you never call is different from a medium-severity one in the exact function you need. Context matters more than severity scores.
9. Check if the package uses OpenSSF Scorecard. The Open Source Security Foundation publishes automated security scorecards for open-source projects. Look up the package on securityscorecards.dev. A score below 4/10 means the project has weak branch protection, no signed releases, or missing CI checks. This is not a dealbreaker on its own, but it tells you how seriously the maintainers take supply chain hygiene.
10. Verify the package has a security policy. Check for a SECURITY.md in the repo. If there is no documented way to report a vulnerability, the maintainers have no process for handling one. This matters when — not if — a CVE hits. You want to depend on projects where someone will actually respond to a disclosure.
Do you actually need this dependency?
11. Measure the dependency against building it yourself. Not every package earns its place. If you need left-pad, write it. If you need a full OAuth2 PKCE implementation, use a library. The decision boundary is: does this package contain domain expertise I would get wrong, or is it convenience code I could write in an afternoon? Every dependency is an ongoing liability — maintenance, security monitoring, breaking changes. The threshold for adding one should be higher than most teams set it.
12. Pin the version and enable lockfile integrity checks. Once you decide to adopt, pin to an exact version in package.json — not a range. Enable npm config set package-lock=true and make sure your CI validates the lockfile integrity hash. This means a compromised version cannot silently enter your build through a semver range bump. Use npm ci in CI/CD, never npm install, so the lockfile is the source of truth and any mismatch fails the build.
“npm install is not a convenience command. It is a trust decision with production consequences.”
What should your team do right now?
If you do nothing else today, run npm audit on your production projects and check whether your CI pipeline uses npm ci or npm install. That single change — enforcing lockfile integrity — would have prevented the majority of supply chain incidents that hit JavaScript projects in the last three years. The rest of this checklist is defense in depth. Start with the lockfile.
- Verify the package publisher matches the known maintainer
- Compare the npm tarball against the GitHub source
- Confirm the version maps to a tagged release
- Read install scripts before running npm install
- Audit the full transitive dependency tree
- Check last commit date and maintainer responsiveness
- Evaluate the bus factor — solo maintainer = higher risk
- Run vulnerability scans (npm audit, Snyk, Socket.dev)
- Look up the OpenSSF Scorecard rating
- Verify a SECURITY.md exists in the repo
- Assess whether you actually need this dependency
- Pin exact versions and enforce lockfile integrity in CI





