How to Check if an npm Package Is Safe (2026 Guide)
Seven checks to run before installing any npm package, the red flags of malicious code, and how to automate protection for the dependencies you can't vet by hand.
Short answer: To check if an npm package is safe, verify five things before you install: the exact package name (typosquats are the #1 trap), the linked GitHub repository and maintainer activity, the package's install scripts (preinstall/postinstall hooks are where most malware runs), known advisories on OSV.dev or the GitHub Advisory Database, and the actual published code on the npm registry — which can differ from what's on GitHub. For dependencies you already have, run a scanner against your lockfile.
That's the two-minute version. The rest of this guide walks through each check step by step, the red flags that should stop an install cold, and how to automate all of this so you don't have to do it manually for every one of the hundreds of transitive dependencies a modern project pulls in.
Why does npm package safety matter more now?
Because the attacks stopped being rare. In September 2025, attackers phished a maintainer and shipped malicious versions of chalk, debug, and more than a dozen other packages that together see billions of downloads a week. Weeks later, the Shai-Hulud worm automated the whole playbook: it stole npm tokens from infected machines and used them to republish malicious versions of every package the victim maintained — a self-replicating supply-chain attack that compromised hundreds of packages.
The volume keeps climbing. Sonatype's 2026 State of the Software Supply Chain report counted more than 454,600 new malicious open-source packages in 2025 — a 75% jump year over year — and npm is the most-targeted registry by a wide margin. The uncomfortable truth: a package being popular, or having been safe last month, no longer tells you it's safe today.
How do you check an npm package before installing it?
Here are the seven checks, in the order that catches the most problems fastest.
1. Read the name character by character
Typosquatting — publishing lodahs to catch people who meant lodash — is still one of the most common tricks because it works. Before you run npm install, confirm the exact spelling against the project's official docs or GitHub README, not a search result or an AI-generated suggestion. Scoped lookalikes (@types-node/... instead of @types/node) count too.
2. Check the registry metadata
Run npm view <package>. In one command you get the latest version, publish date, license, maintainers, and repository link — without downloading any code. Be suspicious of: a version published in the last day or two (compromised versions are usually caught and pulled within hours), a maintainer list that recently changed, or no repository link at all.
3. Verify the GitHub repository actually matches
Anyone can put any repo URL in package.json. Click through: does the repo exist, does it have real history and issues, and does its package name match the one you're installing? A polished README pointing at a popular project's repo is a classic cover for a malicious clone.
4. Look up known advisories
Search the package on OSV.dev, which aggregates the GitHub Advisory Database, npm's own malware reports, and other sources. If the exact version you're about to install has a MAL- or GHSA- advisory against it, stop. This is the fastest check on the list and catches every known-bad version.
5. Inspect the install scripts
Run npm view <package> scripts. The preinstall, install, and postinstall hooks execute arbitrary code on your machine the moment you install — this is where the majority of npm malware detonates. Legitimate uses exist (native builds, downloading prebuilt binaries), but an install script in a small utility package that has no native code is a red flag worth investigating.
6. Read the published code, not the GitHub code
What's on npm can differ from what's on GitHub — attackers publish a clean repo and a poisoned tarball. Preview the actual registry contents without executing anything: npm pack <package> --dry-run lists the files, or browse the published source on a viewer like npmjs.com's code tab. Scan for the patterns in the red-flag table below.
7. Gauge maintenance honestly
Recent commits, responsive issues, and multiple maintainers are good signs. Raw download counts are not — they're trivially inflated by bots, so OWASP's npm security guidance treats popularity as supporting evidence, never proof. And as the chalk/debug incident showed, even a genuinely popular, well-maintained package can ship a malicious version for a few hours.
What are the red flags of a malicious npm package?
When you're skimming a package's published code or metadata, these are the signals that matter most:
| Red flag | Why it matters |
|---|---|
| Long base64 or hex-encoded strings | Standard way to hide a payload from casual review |
eval() or new Function() on decoded data | Executes that hidden payload at runtime |
| Network calls in install scripts | fetch, http.get, or curl during install usually means data exfiltration or a second-stage download |
Reads of process.env, .npmrc, or SSH/cloud credential paths | Token and credential theft — the fuel for worms like Shai-Hulud |
| Version published within the last 24–48 hours | Most compromised versions are caught and unpublished quickly; waiting out new releases avoids the window |
| Name one character off a popular package | Typosquat |
| Repo link missing, dead, or pointing at a different project | No way to audit provenance |
| Obfuscated or minified source in the tarball with no build pipeline | Libraries ship readable source; deliberate obfuscation in a published package hides intent |
No single row proves malice — install scripts and new releases are often legitimate. Two or three together, in a package you've never used before, is when you walk away.
How do you check packages you've already installed?
Pre-install vetting doesn't help with the 1,000+ transitive dependencies already in your node_modules. For those:
- Run
npm auditfor a baseline. It checks your dependency tree against npm's advisory data — useful, but it only knows about disclosed CVEs and flags nothing about malware published minutes ago. (We've written about where npm audit falls short.) - Scan your lockfile against OSV data. Tools like
osv-scanner— or our free lockfile scan, which checks every exact version in yourpackage-lock.jsonagainst OSV.dev advisories includingMAL-malware records — catch known-bad versions thatnpm auditmisses. - Pin and commit your lockfile. A committed lockfile means installs are reproducible and a hijacked patch release can't slide in silently on the next
npm ci.
How do you make safe installs the default?
Manual vetting doesn't scale to every install by every developer, every CI run, and — increasingly — every AI coding agent that runs npm install on your behalf. Four settings do most of the work automatically:
- Disable install scripts by default:
npm config set ignore-scripts true. This neuters the most common execution vector. Re-enable per-package only when a dependency genuinely needs a build step. - Enforce a minimum release age. pnpm supports
minimumReleaseAgeto refuse versions published in the last N minutes — most malicious versions are pulled within hours, so even a 24-hour buffer removes most of the risk window. - Use lockfiles +
npm ciin CI so builds install exactly what was reviewed, nothing newer. - Put a firewall at the registry boundary. The checks above depend on humans remembering to run them. A registry-level firewall doesn't: point npm at a filtering registry (for InstallSafe,
npm config set registry https://r.installsafe.io) and every install — from your laptop, CI, or an AI agent — is checked against OSV advisory data before the tarball is served. Flagged versions are blocked; everything else passes through byte-for-byte. To be clear about the limits: an advisory-based firewall blocks known-bad versions, not zero-hour malware nobody has flagged yet — which is exactly why it belongs alongside the release-age delay andignore-scripts, not instead of them.
That layered setup — name vigilance and script inspection for the packages you add deliberately, plus automated advisory blocking and release-age delays for everything else — is what "checking if a package is safe" looks like when it has to work at the speed modern teams (and their AI agents) install code.
Frequently asked questions
Is a popular npm package automatically safe?
No. Download counts can be gamed, and even genuinely popular packages get compromised — the September 2025 chalk/debug incident shipped malware in packages with billions of weekly downloads. Popularity means problems get noticed faster, not that they don't happen.
Does npm scan packages for malware?
npm removes malicious packages after they're reported and publishes malware advisories, but there is no gate that stops a malicious package from being published in the first place. Detection is reactive, which is why the first hours after a malicious publish are the dangerous window.
What does npm audit actually check?
npm audit compares your installed versions against npm's advisory database of disclosed vulnerabilities. It's a useful baseline but won't flag brand-new malware, typosquats with no advisory yet, or suspicious install scripts.
How do I check a package without installing it?
Use npm view <package> for metadata and scripts, npm pack <package> --dry-run to list the tarball contents, and OSV.dev or the GitHub Advisory Database for known advisories. None of these execute any package code.
What's the single highest-impact protection?
If you only do one thing: disable install scripts (ignore-scripts true) and commit your lockfile. If you can do two, add an advisory-checking layer — a lockfile scanner or a registry firewall — so known-bad versions are caught without anyone having to remember to look.
Want to know if anything already in your project is flagged? Run a free lockfile scan — it checks every exact version in your lockfile against OSV.dev advisories, including malware records, in about a minute.