Guide

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 - socktio for socket.io, passsport1 for passport
  • Punctuation swaps - ethers.json where the real package is ethers, 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 @scope reusing 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 postinstall hook deserves a look.
  • Version numbers that are absurdly high. 99.0.0 on a package whose real line is 2.x is 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/utils is 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, eval of decoded content, dynamic require built 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-scripts installs 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.

Check your own dependencies

Paste a lockfile and see whether any of this applies to you. It runs entirely in your browser - nothing is uploaded.

Check your dependencies

Related guides