How to tell if an npm package is malicious
Most advice here is either unusable ("read the source of every dependency") or superstition ("avoid packages with few downloads"). These are the signals that have actually correlated with the incidents we track.
Updated · Precursor Security
Check the name before anything else
Typosquatting remains the single most common vector in our database, and it is the easiest to defend against because it costs you five seconds.
Before installing, compare the name character by character against the package you meant to install. The patterns that recur:
- Transpositions and doubled letters -
socktioforsocket.io,passsport1forpassport - Punctuation swaps -
ethers.jsonwhere the real package isethers, or a hyphen where the original has a dot - Plausible suffixes -
-master,-git,.git,-js, which look like repository names rather than package names - Scope impersonation - an attacker-owned
@scopereusing the exact package names of a real internal or public scope
The highest-risk moment is copying an install command from a blog post, a Stack Overflow answer, or LLM-generated output. None of those verify that the package exists, let alone that it is the right one.
Signals that genuinely predict trouble
- A brand-new version of an old, stable package. Maintainer account takeover looks exactly like this: a package that has not shipped in two years suddenly publishes a patch release.
- An install script on a package that has no reason to build anything. A pure-JavaScript utility with a
postinstallhook deserves a look. - Version numbers that are absurdly high.
99.0.0on a package whose real line is2.xis the classic dependency-confusion pattern - the attacker wants the resolver to prefer their public package over your private one. - A package that exists on the public registry but is named like your internal tooling. If you have a private
@company/utils, someone publishing a public@company/utilsis not a coincidence. - Publish timestamps clustered across many similar names. Fifteen packages with related names published in the same hour is a campaign, not a coincidence.
Signals that look alarming but usually are not
Worth knowing so you do not waste effort:
- Low download counts. Every legitimate package starts at zero. Download count tells you about popularity, not intent, and attackers inflate it trivially.
- No README, or a sparse one. Plenty of genuine internal and utility packages ship with nothing. Meanwhile sophisticated malicious packages often have excellent READMEs, because looking legitimate is the entire point.
- Minified or bundled code. Common in legitimate distributions. What matters is obfuscation that serves no build purpose - long hex string arrays,
evalof decoded content, dynamicrequirebuilt from string fragments. - A recent first-publish date. New is not malicious. New and near-identical to a popular package is.
Checking without installing
The awkward part of inspecting an npm package is that the obvious way to get it is to install it, which is the thing you are trying to avoid. Some options that do not execute anything:
npm view <package>shows metadata - versions, publish dates, maintainers - without downloading a tarball.npm pack <package>downloads the tarball without running install scripts, so you can extract and read it.npm install --ignore-scriptsinstalls without executing hooks. Not a guarantee - import-time payloads still run when your code loads the module - but it blocks the most common path.- Read the published file list. A package whose tarball contains files nothing in the manifest references is worth a closer look.
And for the case where it is already in your tree: check the lockfile against known compromises rather than trying to eyeball 900 transitive dependencies.
Common questions
- Is a package with millions of downloads safe?
- Safer, but not safe. Several of the largest incidents we track hit packages with tens of millions of weekly downloads, via maintainer account takeover. Popularity raises the bar for the attacker and raises the payoff at the same time.
- Does a scoped package (
@org/name) mean it is official? - No. Anyone can create a scope. Scope impersonation - registering a scope that looks like a company's and republishing their package names - is a recurring pattern in our database.
- Should I just vendor my dependencies?
- It helps with reproducibility and removes registry availability as a runtime dependency, but it does not help if you vendored a compromised version. You still need to know which versions are bad.