MagmaNex LogoMagmaNex
Home/Blog/Supply Chain Attacks: npm and PyPI Package Poisoning
Supply Chain Attacks: npm and PyPI Package Poisoning
SecurityJune 10, 2026· 8 min read

Supply Chain Attacks: npm and PyPI Package Poisoning

How do software supply chain attacks work? We break down typosquatting, dependency confusion, and malicious post-install scripts, then give developers an actionable defence checklist.

#supply chain#npm#pypi#dependency security#devsecops#sbom

Supply Chain Attacks: npm and PyPI Package Poisoning

A modern application is built on hundreds, often thousands, of open-source dependencies. The code you actually wrote is perhaps five percent of the total. Everything else arrives on your machine through npm install or pip install — packages you never see and mostly never read. That is precisely where attackers aim: your weakest link is not your own code, it is the dependencies you trust.

What is a supply chain attack?

A supply chain attack means compromising something the target trusts (a library, a package, a build tool) instead of attacking the target directly. The attacker poisons a single popular package; because that package sits in the dependency tree of thousands of projects, the poison spreads on its own. The 2020 SolarWinds incident was the best-known enterprise-scale example of this logic — but on registries like npm and PyPI, the same pattern repeats every week at much smaller scales.

The real scope of the danger is this: a poisoned package runs not only on your production servers but also on developer machines and inside CI/CD pipelines. A post-install script can silently exfiltrate your environment variables, registry tokens, or SSH keys during a build.

Real attack vectors

Typosquatting

The attacker publishes a name that closely resembles a popular package: reqeusts, python-dateutils instead of python-dateutil, 1odash instead of lodash. A single mistyped character in a rushed command is enough to pull the malicious package into your project.

Dependency confusion

Companies often use internal (private) packages like acme-internal-auth. The attacker uploads a package with the same name to the public registry, but with a higher version number. A misconfigured package manager prefers the "newer" version and pulls the public, poisoned one. In 2021 this technique reached the internal networks of many large companies.

Compromised maintainer accounts

Sometimes there is no need to write a new package at all. The attacker takes over the npm account of a legitimate package's maintainer (leaked password, phishing, session hijacking) and adds malicious code to the existing, trusted package as a "patch." Users receive the poison through an automatic update without ever noticing.

Malicious post-install scripts

Both npm (scripts.postinstall) and PyPI (setup.py execution) allow arbitrary code to run during installation. This is the favourite attack surface, because anyone who types npm install unknowingly grants the attacker's code permission to run with their own privileges.

"scripts": {
  "postinstall": "node ./harmless-looking-setup.js"
}

That innocent-looking file can quietly send your ~/.aws/credentials to a remote server in the background.

Why is it so dangerous?

  • Scale: A single poisoned dependency runs across thousands of pipelines and developer machines at the same time.
  • Trust: Nobody reads the source of every dependency; the whole system is built on trust.
  • Transitive dependencies: The package you added directly may be clean, but a dependency of its dependency may be poisoned. Most developers never see that depth.
  • Privileged context: CI environments often have access to publish tokens, cloud keys, and signing certificates. The poison runs right next to your most valuable secrets.

A defence checklist for developers

No single measure is enough; defence must be layered.

1. Use lockfiles and pin versions

package-lock.json, yarn.lock, or poetry.lock records the exact version and integrity hash of every dependency. Always commit the lockfile to version control and use npm ci (a lockfile-only install) in CI. When starting a new project, a solid package.json Generator helps you build a clean foundation with versions stated explicitly.

2. Verify integrity / checksums

When you download a package or release file manually, compare it against the SHA-256 value the publisher announced. Use the SHA-256 Generator to quickly produce a file's hash, and Hash Compare to check two values side by side. Even a single-character difference shows the file has been tampered with.

3. Give CI tokens least privilege

Your CI workflows should hold only the permissions they actually need. Read-only tokens, short-lived credentials, and narrowly scoped grants limit the damage a compromised dependency can do. Never commit secrets to the repo; a solid .gitignore Generator keeps .env, credential files, and build artefacts from slipping into version control.

4. Review post-install scripts

You can disable scripts with npm install --ignore-scripts, and you can actually read a package's scripts section before adding a new dependency. If you see a suspicious postinstall, think twice before pulling the package in.

5. Generate an SBOM (Software Bill of Materials)

An SBOM is an inventory of every component and version in your project. An SBOM in CycloneDX or SPDX format lets you answer "do we have this package?" in seconds when a new vulnerability is disclosed.

6. Enable 2FA on registry accounts

Enforce two-factor authentication on npm and PyPI maintainer accounts. Because maintainer-account takeover is the most devastating vector, 2FA alone blocks a large share of attacks.

Summary

Supply chain security is not a one-time task but an ongoing discipline. Pin your dependencies, verify their integrity, run your CI with least privilege, read the scripts, and protect your accounts with 2FA. Each of these steps is small on its own; together they make the attacker's job considerably harder.

For more tools, browse the Security tools.

Note: All MagmaNex tools run entirely in your browser. Your files and hashes are never uploaded to any server, never sent anywhere.


🛠 Related Tools

📚 Related posts

← All posts🛠 Explore tools