A practical npm supply-chain security guide for small teams: lockfiles, install scripts, dependency review, secrets hygiene, and what to do if you suspect a bad package.

A typical JavaScript project pulls in hundreds, sometimes thousands, of packages written by people you've never met. Each one runs on your laptop, your CI server, or both.
That's the supply-chain problem. You don't need to be targeted for it to hurt you. A single compromised package, installed automatically, can reach your machine, your tokens, and your production environment.
Large companies have security teams for this. Small teams usually don't. The good news is that most of the protection comes from a handful of simple habits, not expensive tools.
In this post, we'll explain how these attacks happen, why small teams are exposed, and the practical steps that reduce your risk the most.
Instead of attacking your code directly, an attacker targets something your code depends on. In the npm ecosystem, that usually looks like one of these:
The common thread is trust. You install a package, and by default your machine runs whatever it says.
Small teams tend to have the same risk factors:
.env files sit on laptops that run npm install all dayNone of this is a failure of skill. It's the result of moving fast. But it means a few deliberate habits go a long way.
Your lockfile (package-lock.json) records the exact versions you tested. Commit it, and in CI and deployments use:
npm cinpm ci installs exactly what the lockfile says and fails if it doesn't match package.json, instead of quietly resolving new versions.
Loose ranges like ^1.2.3 allow new releases to flow in automatically. Consider:
Many malicious versions are caught and removed within hours or days. A short delay, even a few days, avoids most of that window.
Some package managers and update tools now support a minimum release age setting, and others are adding it. Check what your tool supports, and if it doesn't, use your update bot to enforce the delay.
Install scripts run code at install time. You can turn them off:
npm install --ignore-scriptsYou can also set this in your .npmrc. Some packages genuinely need scripts to build native code, so allow those deliberately and keep the rest off. Some newer package managers restrict dependency scripts by default, which is worth knowing about if you are choosing tools.
Before you run npm install some-package, take two minutes to check:
npm auditnpm audit reports known vulnerabilities. It won't catch a brand-new malicious package, so treat it as one layer, not the whole defense. Dedicated scanning tools can add a further layer if your budget allows.
If a malicious package runs on a laptop, it can read whatever that laptop can read. Reduce what's there:
.env files and shell profilesIf you publish packages or deploy from CI:
Add your own real experience here: what happened, how you noticed, what you changed afterward, and what you would do differently. Remove client and project names and sensitive details before publishing.
Move quickly, but calmly:
.env filesIf you aren't sure whether a machine ran malicious code, the safe choice is to treat it as compromised and rebuild it.
Use this as your starting point:
npm cinpm audit run regularlynpm install on a machine that holds real credentialsYou can't remove trust from the npm ecosystem, but you can make it deliberate. A committed lockfile, a short delay on new releases, fewer install scripts, and secrets kept off developer machines will block most of the common attacks, and none of it requires a security team.
At Flitz Interactive, we build and maintain web and mobile applications with security habits built into the development process, from dependency management to deployment. If you'd like help hardening your own setup, we'd be happy to talk it through.