Every npm package in your bundle runs in your users' browsers with your page's origin. A malicious package can read the DOM, form fields like passwords and card numbers, and localStorage. It can also call your API as the user. On top of that, install scripts run on developer machines and in CI, where tokens and secrets live.
Real cases:
- In 2018,
event-streamgot a malicious dependency that targeted one bitcoin wallet app. - In 2021, hijacked versions of
ua-parser-jsinstalled malware. - In 2025, hijacked versions of popular packages such as
chalkanddebugtried to steal crypto from users' browsers.
Defences:
- Commit the lockfile and install with
npm ci, so every build uses the same versions. - Review lockfile changes in pull requests.
- Update on purpose with Dependabot or Renovate. Waiting a few days before taking a brand-new release avoids many hijacks, because they are usually caught fast.
- Run
npm auditin CI, and keep the dependency tree small. - Turn off install scripts where you don't need them (
ignore-scripts). - Use a strict CSP
connect-src, so stolen data has fewer places to go. - Use Subresource Integrity for files you load from a CDN.
- Bundled packages run with your page's origin and can read forms, storage and the DOM.
- Install scripts run on developer machines and in CI, where secrets live.
- Commit the lockfile, install with
npm ciand review lockfile changes. - Update on purpose, and wait a little before taking brand-new releases.
- A strict CSP
connect-srclimits where stolen data can be sent.