unsploitable
← Guides
supply-chaindependenciesnpmpypivscodechrome

Defending Against Supply Chain Attacks

Practical steps to harden your development environment and software supply chain across package ecosystems, editors, and browsers.

A supply chain attack compromises software before it reaches you — by targeting a package you depend on, a tool you run, or an extension you’ve installed. The attacker doesn’t need to breach your systems directly; they only need to compromise something you already trust.

General Principles

These apply regardless of ecosystem.

Every dependency is a trust decision. When you add a dependency you’re trusting its author, every maintainer, the registry, and every transitive dependency it pulls in. Most teams don’t think about this explicitly.

Before adding any dependency, ask:

  • Does it have active maintainers and a public source repository?
  • When was it last published? Dormant packages are more likely to be taken over.
  • How many maintainers does it have? Single-maintainer packages are high-risk — one compromised account poisons everyone downstream.
  • Could you reasonably implement this yourself with less risk?

Pin versions and verify integrity. ^1.2.3 means “install whatever the latest compatible version is.” Pin to exact versions. Commit lockfiles. Where the ecosystem supports it, verify hashes.

Automate monitoring. Use Dependabot or Renovate to surface new versions and known vulnerabilities as PRs. Review those PRs — don’t merge automatically.


By Ecosystem

NPM

NPM’s size makes it a prime target. Supply chain attacks via NPM have hit Twilio, Cloudflare, and Okta.

Use npm ci in automated environments

npm ci installs strictly from package-lock.json and fails if the lockfile doesn’t match package.json. Never use npm install in CI — it can silently update the lockfile.

# Development: update lockfile
npm install

# CI / production: fail if lockfile is inconsistent
npm ci

Audit package integrity

# Check for known vulnerabilities
npm audit

# Verify registry signatures on installed packages (requires npm v9+)
npm audit signatures

Disable install scripts

postinstall and similar lifecycle scripts execute arbitrary code during install. They’re one of the most common attack vectors.

# Per-install
npm ci --ignore-scripts

# Or permanently in your project's .npmrc
ignore-scripts=true

Inspect packages before installing

# See what's in a package without installing it
npm pack <package-name> --dry-run

Red flags: binaries, shell scripts, or network calls in lifecycle hooks.

Watch for typosquatting

coloers instead of colors. loadsh instead of lodash. Always double-check package names — especially ones typed from memory or copied from a blog post.

Pin GitHub Actions to commit SHAs

Tags can be repointed. Commit SHAs cannot.

# Vulnerable — tag can be moved to a different commit
- uses: actions/checkout@v4

# Safe — SHA is immutable
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683

warning

A package that was dormant for months and just published a new version with a different maintainer email is a strong signal of a takeover. Always check release history before updating.

Checklist0/7

PyPI

Python’s ecosystem has similar risks to NPM, with some PyPI-specific quirks worth knowing.

Pin with hashes

pip supports hash verification in requirements files. Generate a pinned requirements file with pip-tools:

pip install pip-tools
pip-compile --generate-hashes requirements.in > requirements.txt

This produces entries like:

requests==2.31.0 \
    --hash=sha256:58cd2187423839... \
    --hash=sha256:942c5a758f98...

Install with hash verification enforced:

pip install --require-hashes -r requirements.txt

If any package fails hash verification, the install aborts.

Use pip-audit in CI

pip-audit scans installed packages against known vulnerability databases:

pip install pip-audit
pip-audit

Always use virtual environments

Never install project dependencies globally. A compromised global package affects every project on your machine.

python -m venv .venv
source .venv/bin/activate
pip install --require-hashes -r requirements.txt

Configure a trusted index

Prevent dependency confusion attacks by explicitly setting your package index:

# pip.conf
[global]
index-url = https://your-internal-registry/simple/
extra-index-url = https://pypi.org/simple/

danger

pip install executes setup.py or pyproject.toml build hooks, which run arbitrary code. Audit packages before adding them to your requirements — you can’t disable this the same way you can disable npm install scripts.

Checklist0/7

VSCode Extensions

VSCode extensions run with your full user account privileges. A malicious extension can read files, exfiltrate credentials, modify code, or establish persistence.

Check publisher verification

Publishers with a blue checkmark badge in the Marketplace have verified their identity with Microsoft. Prefer verified publishers for extensions that touch sensitive contexts: git, SSH, cloud credentials, environment variables.

Inspect the extension before installing

  1. Find the source repository linked from the Marketplace page
  2. Verify it exists and matches the publisher
  3. Review recent commits — has anything unexpected been added?
  4. Check package.json for activationEvents

An extension with "activationEvents": ["*"] runs on every window open. Scrutinise it carefully.

Use workspace extension recommendations

Commit a .vscode/extensions.json to lock in the vetted set for your project:

{
  "recommendations": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"],
  "unwantedRecommendations": []
}

Separate profiles for sensitive work

VSCode profiles let you run with completely different extension sets. Create a minimal profile — zero third-party extensions — for work involving production access, credentials, or sensitive codebases.

warning

Extensions that offer to fix errors or complete tasks by sending your code to an external API are a common attack vector. Audit what data they transmit before trusting them in sensitive repos.

Checklist0/6

Chrome Extensions

Chrome extensions can read and modify every page you visit, intercept network requests, and access clipboard contents. A compromised extension is one of the highest-impact attacks possible on a developer workstation.

Read permissions before installing

Before installing any extension, read every permission it requests. The most dangerous:

  • “Read and change all your data on the websites you visit” — full access to every site
  • “Read your browsing history”
  • Clipboard access
  • Native messaging — can communicate with applications on your machine

Prefer extensions that request only what their stated purpose requires.

Use separate browser profiles

This is the single most effective Chrome defence. Create isolated profiles:

  • Personal — general browsing
  • Work — internal tools, work SaaS
  • Sensitive — banking, password manager, anything high-value

Extensions installed in one profile have zero access to other profiles.

Extensions can be sold and poisoned

A legitimate extension with thousands of users is a valuable target. The original developer sells it; the buyer ships a malicious update. All existing installs auto-update silently.

Consider reviewing changelogs manually before updating extensions, or keeping a minimal extension set that limits your exposure.

tip

For security research or visiting untrusted sites, use a dedicated browser (separate Chromium instance or Firefox) with zero extensions installed. Compartmentalisation limits blast radius.

Checklist0/6