← Alle Neuigkeiten
npm5 Min. Lesezeit

What npm install actually does that nobody reads

Von Seaworthy · 12. Juni 2026

Warehouse storage aisles with shelves full of boxes

Photo by Phillip Flores on Unsplash

The implicit contract you agreed to

When you run npm install, you are not just downloading files. You are granting execution rights to code you have never read, from maintainers you have never vetted, on the machine where your SSH keys, AWS credentials, and CI tokens live.

Nobody frames it that way in the docs. But that is what is happening.

Let me walk you through the three mechanisms that make this genuinely dangerous, with real incidents rather than theoretical warnings.

Postinstall scripts run arbitrary code at install time

Every npm package can declare lifecycle hooks in its package.json:

{
  "scripts": {
    "postinstall": "node setup.js"
  }
}

That script runs automatically when someone installs your package. It has full access to the filesystem, the network, and every environment variable on the machine. No sandbox. No prompt. No warning.

Some packages have legitimate reasons for this: native modules need to compile binaries, some tools write config files. But the mechanism is indistinguishable from a backdoor, which is exactly why attackers use it.

The event-stream incident in 2018 is the canonical example. A popular utility package changed hands to an anonymous contributor. They added a new transitive dependency called flatmap-stream, which contained an encrypted payload that extracted private keys from the Copay Bitcoin wallet app and sent them to an attacker-controlled server. The malicious code ran for two months. It was discovered not by any automated tool but by a developer who happened to audit the source and noticed an encrypted string that had no business being there.

In 2021, ua-parser-js was hijacked. The package had over seven million weekly downloads. The attacker published three malicious versions in rapid succession (0.7.29, 0.8.0, 1.0.0). Each one used a postinstall script to drop a cryptominer. Anyone who ran npm install during that window, with a loosely pinned version range, got the payload. CISA issued a formal advisory.

Both attacks worked because postinstall runs silently, blends into install output, and the average developer does not read node_modules/some-package/scripts/setup.js before it executes.

Typosquatting preys on the speed you work at

The npm registry is public and permissive. Anyone can publish a package with any name that is not already taken. Attackers publish packages with names one or two characters off from popular ones, then wait for developers to mistype.

crossenv versus cross-env is the textbook case. The attacker published a package that wrapped the real functionality of cross-env almost completely, with one addition: a postinstall script that captured all environment variables and sent them, base64-encoded, to a remote server. On a developer machine that is annoying. On a CI runner with deploy keys in the environment, it is catastrophic. The package accumulated millions of installs before it was caught.

The lodash ecosystem has attracted repeated attacks. In 2024, a package called lodasher (note the extra r) shipped a modified version of the AnyDesk remote access utility targeting Windows developers. The version numbers were deliberately close to the real lodash releases, at 4.17.24 versus the genuine 4.17.21, to look plausible in a package-lock.json diff.

These attacks work because of how we actually install packages. You see a Stack Overflow answer, you copy the install command, you run it. Or you let an AI assistant suggest a package name. The extra character is invisible at the speed most people work.

Transitive dependencies are the real attack surface

Here is a practical exercise. Install create-react-app and count what you actually got:

npm install create-react-app
ls node_modules | wc -l

The answer, historically, has been around 1,200 packages. You wanted one. You got over a thousand. You have read the source of none of them.

Every one of those packages has a maintainer. Every maintainer is a potential target. Accounts get compromised, credentials get phished, maintainers burn out and hand off projects to whoever asks. The colors and faker incident in January 2022 was not even a malicious attack in the usual sense: the original maintainer deliberately sabotaged both packages in protest, breaking thousands of downstream applications overnight. colors had 19,000 dependent packages and 23 million weekly downloads. One person's decision to push bad code cascaded instantly.

The math is uncomfortable. If you have 1,000 transitive dependencies, and each one has a 0.1% annual chance of being compromised in some way, you have a roughly 63% chance of exposure per year across your full dependency tree. That is not a scare statistic I made up: it is just how probability compounds.

What you can actually do

The honest answer is you cannot fully eliminate this risk. But you can shrink it meaningfully.

Run npm install --ignore-scripts for packages where you know scripts are not needed. This disables postinstall hooks entirely. Some packages will break; that is worth knowing about.

Pin exact versions in package-lock.json and commit it. Loose ranges like ^1.2.3 mean the package you tested is not the package that runs in production next Tuesday.

Before installing something new, spend thirty seconds on it: check the npm page for weekly downloads, look at when it was last published, check if the GitHub repo looks maintained. A package with 40 downloads a week and a name one character off from something popular should raise your suspicion immediately.

Run npm audit regularly, but understand what it does and does not catch. It checks for known vulnerabilities in the advisory database. A brand new malicious package published this morning will not appear there.

Consider tools like socket.dev that analyze packages for suspicious patterns rather than just matching against known-bad lists.

The bigger problem

The supply chain attack problem is not going away because it exploits a genuine tension in open source: we depend on a massive amount of code we do not pay for and cannot fully vet. The attack surface grows with every dependency you add, transitively included or not.

Vibe coding makes this worse in a specific way. When an AI suggests adding a package, you often do not pause to think about what else comes with it. The productivity gain is real, and the risk is invisible until it is not.

Seaworthy flags packages with suspicious postinstall scripts and known typosquatted names in your dependency tree as part of its dependency hygiene checks.

Dieser Artikel wurde von KI generiert und fasst öffentlich verfügbare Quellen zusammen.

Von den Machern von Seaworthy

Seaworthy scannt dein Repository nach den Problemen, die in Artikeln wie diesem behandelt werden.

Sicherheitslücken, offengelegte Geheimnisse und Fehlkonfigurationen — erkannt, bevor du bereitstellst. Kostenlos, kein Konto nötig.

$ npx seaworthycode