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 ciAudit package integrity
# Check for known vulnerabilities
npm audit
# Verify registry signatures on installed packages (requires npm v9+)
npm audit signaturesDisable 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=trueInspect packages before installing
# See what's in a package without installing it
npm pack <package-name> --dry-runRed 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@11bd71901bbe5b1630ceea73d27597364c9af683warning
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.
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.txtThis produces entries like:
requests==2.31.0 \
--hash=sha256:58cd2187423839... \
--hash=sha256:942c5a758f98...Install with hash verification enforced:
pip install --require-hashes -r requirements.txtIf 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-auditAlways 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.txtConfigure 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.
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
- Find the source repository linked from the Marketplace page
- Verify it exists and matches the publisher
- Review recent commits — has anything unexpected been added?
- Check
package.jsonforactivationEvents
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.
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.