Software supply chain attacks have exploded in frequency and sophistication. In 2025 alone, thousands of malicious packages were discovered on npm, PyPI, and Docker Hub. As developers, every npm install or pip install is an act of trust — and attackers know it. This guide walks you through practical, actionable steps to lock down your dependency chain in 2026.
What Are Supply Chain Attacks?
A supply chain attack targets the tools and libraries you depend on rather than your code directly. Instead of finding a vulnerability in your application, attackers compromise a package you trust — injecting malware, backdoors, or credential stealers into legitimate-looking dependencies.
Common attack vectors include:
- Typosquatting: Publishing
requetsinstead ofrequests - Account takeover: Hijacking a maintainer’s npm/PyPI credentials
- Dependency confusion: Exploiting private vs public package resolution
- Malicious Docker images: Trojanized base images on Docker Hub
- Build pipeline injection: Compromising CI/CD workflows
Securing npm Dependencies
1. Use Lockfiles Religiously
Always commit package-lock.json and use npm ci instead of npm install in CI pipelines. This ensures deterministic builds:
# In CI/CD — never use npm install
npm ci --ignore-scripts
# Audit after install
npm audit --audit-level=highThe --ignore-scripts flag is critical — most malicious packages execute their payload via postinstall scripts.
2. Enable npm Provenance
npm now supports provenance attestations, linking packages to their source repo and build:
# Check provenance of a package
npm audit signatures
# When publishing your own packages
npm publish --provenanceOnly install packages with verified provenance when possible. Check for the green checkmark on npmjs.com.
3. Pin and Review Dependencies
// package.json — pin exact versions
{
"dependencies": {
"express": "4.21.2",
"lodash": "4.17.21"
}
}
// .npmrc — restrict install sources
registry=https://registry.npmjs.org/
@mycompany:registry=https://npm.mycompany.com/Securing Python Dependencies
1. Hash-Verified Installs
pip supports hash checking to ensure you get exactly the package you expect:
# Generate hashes
pip-compile --generate-hashes requirements.in -o requirements.txt
# Install with hash verification
pip install --require-hashes -r requirements.txtThis prevents any package substitution or tampering. If a single byte changes, the install fails.
2. Use pip-audit for Vulnerability Scanning
# Install the auditor
pip install pip-audit
# Scan your environment
pip-audit
# Scan a requirements file
pip-audit -r requirements.txt
# Output in JSON for CI integration
pip-audit -f json -o audit-results.json3. Configure Trusted Publishers on PyPI
If you maintain packages, set up Trusted Publishers to link your GitHub Actions workflow directly to PyPI — no more storing API tokens:
# .github/workflows/publish.yml
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- run: pip install build && python -m build
- uses: pypa/gh-action-pypi-publish@release/v1Securing Docker Images
1. Always Pin Image Digests
Tags are mutable — latest can change at any time. Pin by SHA256 digest:
# Bad — mutable tag
FROM python:3.12-slim
# Good — pinned digest
FROM python:3.12-slim@sha256:a3e58f9399353be051735f09be0316bfdeab571a5c6a24ef78a7f6f4080a3b9e2. Scan Images Before Deployment
# Using Trivy (recommended)
trivy image myapp:latest
# Scan and fail on HIGH/CRITICAL
trivy image --severity HIGH,CRITICAL --exit-code 1 myapp:latest
# Scan a Dockerfile before building
trivy config Dockerfile3. Use Docker Content Trust
# Enable content trust globally
export DOCKER_CONTENT_TRUST=1
# Now pulls will only succeed for signed images
docker pull nginx:latest # Only works if signedCI/CD Pipeline Hardening
Your build pipeline is a high-value target. Here’s a GitHub Actions workflow that incorporates supply chain security:
name: Secure Build
on: [push]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Verify dependency integrity
run: |
npm ci --ignore-scripts
npm audit signatures
npm audit --audit-level=high
- name: Run SAST scan
uses: github/codeql-action/analyze@v3
- name: Build with SBOM
run: |
npm run build
npx @cyclonedx/cyclonedx-npm --output-file sbom.json
- name: Container scan
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
severity: HIGH,CRITICAL
exit-code: 1Generate a Software Bill of Materials (SBOM)
An SBOM is your ingredient list — it documents every dependency in your project. In 2026, many organizations require them:
# For Node.js projects
npx @cyclonedx/cyclonedx-npm --output-file sbom.json
# For Python projects
pip install cyclonedx-bom
cyclonedx-py environment -o sbom.json
# For Docker images
trivy image --format cyclonedx -o sbom.json myapp:latestQuick Security Checklist
- ✅ Lock dependencies with lockfiles and hash verification
- ✅ Run
npm audit/pip-audit/trivyin every CI build - ✅ Pin Docker images by digest, not tag
- ✅ Disable postinstall scripts in CI (
--ignore-scripts) - ✅ Enable npm provenance and Docker Content Trust
- ✅ Generate and store SBOMs for every release
- ✅ Use Dependabot or Renovate for automated dependency updates
- ✅ Scope private registries to prevent dependency confusion
- ✅ Review new dependencies before adding them (check maintainers, download counts, last update)
- ✅ Enable 2FA on all package registry accounts
Conclusion
Supply chain security isn’t optional anymore — it’s a fundamental part of modern development. The good news is that the tooling has matured significantly. By implementing lockfile verification, hash checking, image scanning, and SBOM generation, you can dramatically reduce your attack surface. Start with one ecosystem, get it locked down, then expand. Your future self (and your users) will thank you.

Leave a Reply